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
检查对象的实际类型,从而避免运行时错误。