0Pricing
Java Academy · 课时

实际应用中的类型转换

在数值计算和面向对象编程的继承层次结构等实际场景中应用类型转换

实际应用中的类型转换 是 CoddyKit 上的免费 Java Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。

实践中的类型转换

在真实的 Java 代码中,类型转换随处可见:数值计算、面向对象的类层次结构、泛型集合以及旧版 API。本课将介绍实际使用中的模式和常见陷阱。

向上转型:多态

向上转型会将子类型转换为超类型。它始终安全且会隐式进行,不需要类型转换运算符。这样便可以实现多态。

class Payment {}
class CreditCardPayment extends Payment {
    public void authorizeCard() {}
}

CreditCardPayment cc = new CreditCardPayment();
Payment p = cc; // implicit upcast — always safe

// p.authorizeCard(); // Compile error — Payment doesn't have this method
// need downcast to access subclass methods

向下转型:访问子类型成员

向下转型会将超类型引用转换回原始子类型。它需要显式类型转换;如果对象实际上不是该子类型,就会抛出 ClassCastException。

Payment p = new CreditCardPayment();

// Downcast to access CreditCardPayment-specific method
if (p instanceof CreditCardPayment cc) {
    cc.authorizeCard(); // safe with pattern matching
    System.out.println("Card authorized");
}

// Unsafe downcast without check:
try {
    BankTransfer bt = (BankTransfer) p; // ClassCastException!
} catch (ClassCastException e) {
    System.out.println("Wrong type!");
}

计算中的数值类型转换

整数除法会截断。请在除法前转换为 double,以获得精确结果。这是 Java 中最常见的算术错误之一。

int totalRevenue = 1000;
int months = 3;

// Integer division — truncates!
double wrong = totalRevenue / months;
System.out.println(wrong); // 333.0 (not 333.33)

// Correct: cast one operand to double first
double correct = (double) totalRevenue / months;
System.out.println(correct); // 333.3333333333333

集合中的类型转换(泛型之前)

旧代码经常将对象存储在原始集合中。取出具有具体类型的值时需要进行向下转型,但请始终先使用 instanceof 检查。

import java.util.*;

// Legacy raw list (pre-Java 5 style)
List legacyList = new ArrayList();
legacyList.add("Alice");
legacyList.add(42);

for (Object item : legacyList) {
    if (item instanceof String s) {
        System.out.println("Name: " + s.toUpperCase());
    } else if (item instanceof Integer n) {
        System.out.println("Score: " + (n * 2));
    }
}

使用接口进行类型转换

对象可以转换为它所实现的任意接口,从而可以在要求该接口的上下文中使用它。

interface Printable { void print(); }
interface Saveable  { void save(); }

class Report implements Printable, Saveable {
    public void print() { System.out.println("Printing report"); }
    public void save()  { System.out.println("Saving report"); }
}

Object obj = new Report();

if (obj instanceof Printable p) p.print();
if (obj instanceof Saveable s) s.save();

数组的类型转换

数组类型有自己独立的层次结构。String[] 是 Object[] 的子类型。数组类型转换遵循与对象相同的规则。

String[] names = {"Alice", "Bob"};
Object[] objs = names;   // upcast — implicit

objs[0] = "Charlie";     // OK — still a String

try {
    objs[0] = 42;          // ArrayStoreException at runtime!
} catch (ArrayStoreException e) {
    System.out.println("Cannot store Integer in String[]");
}

// Downcast back
String[] restored = (String[]) objs;

电子商务示例:支付分派

一个实际示例是:根据支付对象的运行时类型,将请求分派给正确的支付处理器。

interface Payment { double amount(); }
record CreditCard(String last4, double amount) implements Payment {}
record CryptoPayment(String wallet, double amount) implements Payment {}
record BankWire(String iban, double amount) implements Payment {}

static void process(Payment p) {
    switch (p) {
        case CreditCard cc     -> System.out.println("Charging card *" + cc.last4());
        case CryptoPayment cp  -> System.out.println("Sending to wallet " + cp.wallet());
        case BankWire bw       -> System.out.println("Wiring to IBAN " + bw.iban());
    }
}

process(new CreditCard("4242", 99.99));
process(new CryptoPayment("0xABCD", 0.05));

转换为 Number 以执行通用数学运算

Number 超类让您可以对任意数字类型执行通用数值运算:先向上转型为 Number,然后调用 doubleValue()。

import java.util.List;

List<Number> numbers = List.of(1, 2.5, 3L, 4.0f);

double sum = 0;
for (Number n : numbers) {
    sum += n.doubleValue(); // works for int, double, long, float
}
System.out.printf("Sum: %.1f%n", sum); // 10.5

安全的类型转换工具方法

这是一个可复用的工具方法:类型转换失败时不抛出异常,而是返回空的 Optional,非常适合管道式代码。

import java.util.Optional;

public static <T> Optional<T> safeCast(Object obj, Class<T> clazz) {
    return clazz.isInstance(obj)
        ? Optional.of(clazz.cast(obj))
        : Optional.empty();
}

// Usage
Object val = "hello";
safeCast(val, String.class)
    .ifPresent(s -> System.out.println(s.toUpperCase())); // HELLO

safeCast(val, Integer.class)
    .ifPresentOrElse(
        n -> System.out.println(n),
        () -> System.out.println("Not an Integer") // prints this
    );

应避免的常见错误

请注意以下常见的类型转换错误:

  • 忘记在除法前进行类型转换:int/int 始终得到整数
  • 未检查 instanceof 就向下转型 → ClassCastException
  • 混淆向上转型(安全)和向下转型(有风险)
  • 混淆包装类型的转换方式:(int) longVal 与 longVal.intValue()
// Mistake 1: integer division
double avg = 7 / 2;            // 3.0 — WRONG
double fixed = 7.0 / 2;        // 3.5 — correct

// Mistake 2: unwrapping Long as int
Long bigId = 1234567890123L;
// int id = (int) bigId;  // compiles but truncates!
long id = bigId;           // correct

System.out.println(avg);   // 3.0
System.out.println(fixed); // 3.5
System.out.println(id);    // 1234567890123

快速检查

以下代码的输出是什么?

int a = 7;
int b = 2;
double result = (double) a / b;
System.out.println(result);

总结:实践中的类型转换

要点:

  • 向上转型(子类型 → 超类型)是隐式的,并且始终安全
  • 向下转型(超类型 → 子类型)需要显式类型转换;请先使用 instanceof
  • instanceof 模式匹配可在同一个表达式中完成检查和类型转换
  • 除法前将被除数转换为 double,以避免整数截断
  • 使用 switch 模式匹配进行清晰的基于类型的分派
  • 构建 safeCast 工具,以便使用 Optional 而不是异常

常见问题解答

「实际应用中的类型转换」课时是免费的吗?

是的 — 「实际应用中的类型转换」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「实际应用中的类型转换」这节课中我会学到什么?

在数值计算和面向对象编程的继承层次结构等实际场景中应用类型转换 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「实际应用中的类型转换」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 基本类型与引用类型
  2. 扩大转换与缩小转换
  3. instanceof 运算符
  4. 实际应用中的类型转换
← 返回 Java Academy