102. Java 继承 - 对象的类型转换
在 Java 中,每个对象都有一个与之关联的数据类型,即它的类类型。我们可以通过创建对象时指定的类来确定它的类型。例如:
MountainBike myBike = new MountainBike();
在这个例子中,myBike 的类型是 MountainBike。
继承关系与类型转换
MountainBike 类是从 Bicycle 类继承而来的,而 Bicycle 类又继承自 Object 类。因此,MountainBike 既是 Bicycle 的一个子类,也是 Object 的一个子类。换句话说,MountainBike 是 Bicycle 类型的对象,也可以是 Object 类型的对象。也就是说,MountainBike 可以用在需要 Bicycle 或 Object 类型对象的地方。
但是,这种转换是单向的。也就是说,Bicycle 可以是 MountainBike 的父类,但 Bicycle 不能自动转换为 MountainBike。同样,Object 类型的对象可以是 MountainBike 或 Bicycle 类型的对象,但并不是所有 Object 类型的对象都能转换成这两种类型。
隐式类型转换(Implicit Casting)
如果我们写:
Object obj = new MountainBike();
在这段代码中,obj 被声明为 Object 类型,并被赋值为 MountainBike 类型的对象。由于 MountainBike 是 Object 的子类,所以 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检查对象的实际类型,从而避免运行时错误。