102. Java 继承 - 对象的类型转换

23 阅读3分钟

102. Java 继承 - 对象的类型转换

Java 中,每个对象都有一个与之关联的数据类型,即它的类类型。我们可以通过创建对象时指定的类来确定它的类型。例如:

MountainBike myBike = new MountainBike();

在这个例子中,myBike 的类型是 MountainBike

继承关系与类型转换

MountainBike 类是从 Bicycle 类继承而来的,而 Bicycle 类又继承自 Object 类。因此,MountainBike 既是 Bicycle 的一个子类,也是 Object 的一个子类。换句话说,MountainBikeBicycle 类型的对象,也可以是 Object 类型的对象。也就是说,MountainBike 可以用在需要 BicycleObject 类型对象的地方。

但是,这种转换是单向的。也就是说,Bicycle 可以是 MountainBike 的父类,但 Bicycle 不能自动转换为 MountainBike。同样,Object 类型的对象可以是 MountainBikeBicycle 类型的对象,但并不是所有 Object 类型的对象都能转换成这两种类型。

隐式类型转换(Implicit Casting)

如果我们写:

Object obj = new MountainBike();

在这段代码中,obj 被声明为 Object 类型,并被赋值为 MountainBike 类型的对象。由于 MountainBikeObject 的子类,所以 MountainBike 对象可以隐式地转换为 Object 类型,这称为 隐式类型转换(Implicit Casting)。在这种情况下,obj 既是 Object 类型的对象,又是 MountainBike 类型的对象,直到它被分配给另一个不是 MountainBike 的对象为止。

显式类型转换(Explicit Casting)

另一方面,如果我们写:

MountainBike myBike = obj;

这会导致编译时错误,因为编译器无法知道 obj 是否真的是 MountainBike 类型的对象。为了告诉编译器,我们希望将 obj 显式地转换为 MountainBike 类型,我们需要使用显式类型转换:

MountainBike myBike = (MountainBike)obj;

这种类型转换会插入一个运行时检查,以确保 obj 确实是 MountainBike 类型。如果 obj 不是 MountainBike 类型,程序会在运行时抛出 ClassCastException 异常。因此,显式类型转换要求我们承诺该对象确实属于目标类型。

使用 instanceof 进行安全转换

为了避免在运行时发生类型转换异常,我们可以使用 instanceof 运算符先检查对象的实际类型,确保转换是安全的:

if (obj instanceof MountainBike) {
    MountainBike myBike = (MountainBike)obj;
}

在上面的代码中,instanceof 运算符会先检查 obj 是否是 MountainBike 类型的实例。如果 obj 不是 MountainBike 类型,instanceof 运算符会返回 false,程序就不会执行强制转换,从而避免了运行时错误。

完整示例
class Bicycle {
    public void ride() {
        System.out.println("Riding the bicycle.");
    }
}

class MountainBike extends Bicycle {
    public void ride() {
        System.out.println("Riding the mountain bike.");
    }
}

public class Main {
    public static void main(String[] args) {
        Bicycle bike = new MountainBike(); // 隐式类型转换
        bike.ride(); // 输出:Riding the mountain bike.

        // 强制转换
        if (bike instanceof MountainBike) {
            MountainBike myBike = (MountainBike)bike; // 显式类型转换
            myBike.ride(); // 输出:Riding the mountain bike.
        }

        // 错误的转换
        try {
            String obj = "Hello, world!";
            MountainBike myBike = (MountainBike)obj; // 会抛出 ClassCastException
        } catch (ClassCastException e) {
            System.out.println("Error: " + e);
        }
    }
}

在这个完整的示例中,首先我们使用隐式类型转换将 MountainBike 对象赋给了 Bicycle 类型的变量 bike,并调用了 ride() 方法,这时会调用 MountainBike 类的 ride() 方法。然后,我们使用 instanceof 运算符检查类型,确保转换是安全的。如果强制转换发生错误,ClassCastException 异常会被捕获并打印出来。

总结:
  • 隐式类型转换(Implicit Casting):子类对象可以赋给父类类型的变量,不需要显式地转换,编译器会自动处理。
  • 显式类型转换(Explicit Casting):当父类对象被赋给子类类型的变量时,需要显式地使用 (类型) 进行转换,且可能抛出 ClassCastException 异常。
  • instanceof 运算符:在进行显式类型转换前,可以使用 instanceof 检查对象的实际类型,从而避免运行时错误。