Java中向下转换对象的规则
类型转换是最重要的概念之一,它基本上处理隐式或显式将一种数据类型转换为另一种数据类型。在本文中,讨论了对象向下转换的概念。它将持有子对象的父引用变量放到子引用变量中。向下转换不能是隐式的。向下转换的语法是:
Type_A ref1 = new Type_B();
Type_C ref2 = (Type_D) ref1;
在此语句中,执行了两个操作:
- 将 ref1 引用的对象转换为类型 D
- 将此转换后的 D 类型对象分配给 C 类型的引用变量
如果向下转换成功与否,将检查 3 条规则。规则如下所述:
1.检查有效转换
为了使转换有效,类型 A 和类型 D 之间必须有关系。这种关系可以是类型 A 是类型 D 的父级,或者类型 D 是类型 A 的父级,或者类型 A = 类型 D。如果没有这种关系,则会出现编译时错误。该规则由编译器检查,因此它不考虑在 ref1 中创建的对象的类型,即它只考虑类型 A 和类型 D,而不考虑类型 B(这是创建的运行时对象的实际类型)。考虑到这个规则,让我们看看一些满足条件的语句。
Object ref1 = new String();
String ref2 = (String) ref1; // satisfy rule 1
ref1 is of Object type which is parent of String
Object ref1 = new String();
Integer ref2 = (Integer) ref1 ; // satisfy rule 1
ref1 is of Object type which is parent of Integer
String ref1 = new String();
String ref2 = (String) ref1 ; // satisfy rule 1
ref1 is of String type which is same
String ref1 = new String();
String ref2 = (Object) ref1 ; // satisfy rule 1
ref1 is of String type which is child of Object
String ref1 = new String();
String ref2 = (Integer) ref1; // doesn't satisfy rule 1
ref1 is of String type which is not related to Integer
Error: incompatible types: String cannot be converted to Integer
2.检查一个有效的分配
在向下转换之后,对象的类型将被键入 D。我们知道一个对象可以被相同类型或它的父对象引用。这就引出了第二条规则,即 ref2 的类型,C 类型必须是父类型或与 D 类型相同。如果不满足此规则,则编译器将抛出错误。考虑到这个规则,让我们看看一些满足条件的语句。
Object ref1 = new String();
Object ref2 = (String) ref1 ; // satisfy rule 1 & rule 2
downcasted object of String type is referred by parent type Object
Object ref1 = new String();
Integer ref2 = (Integer) ref1; // satisfy rule 1 & rule 2
downcasted object of Integer type is referred by same type
Object ref1 = new String();
String ref2 = (Object) ref1; // satisfy rule 1 but not rule 2
downcasted object of Object type is referred by child class type String
Error: incompatible types: Object cannot be converted to String
String ref1 = new String();
Integer ref2 = (Integer) ref1; // doesn't satisfy rule 1 & rule 2
downcasted object of Integer type is referred by unrelated class type String
Error: incompatible types: String cannot be converted to Integer
3.检查对象的运行时类型的兼容性
如果我们注意到以上两点,它们仅涵盖引用类型和转换类型。我们试图向下转换的对象的实际运行时类型尚未考虑在内。 JVM 现在将考虑此运行时类型来检查有效性。子类对象可以转换为同一个类或父类。这就引出了第三条运行时规则,即类型 D 必须是 ref1 的运行时类型(即类型 B)的父级或相同类型。如果此条件失败,JVM 将在运行时抛出 ClassCastException。考虑到这个规则,让我们看看一些满足条件的语句。
Object ref1 = new String();
Object ref2 = (String) ref1 ; // satisfy rule 1, rul2 & rule 3
downcasted object of String type is same as runtime type String
Object ref1 = new Integer();
Object ref2 = (Number) ref1 ; // satisfy rule 1, rul2 & rule 3
downcasted object of Number type is same parent of runtime type Integer
Object ref1 = new String();
Integer ref2 = (Integer) ref1; // satisfy rule 1, rule 2 but not rule 3
downcasted object of Integer type is not same or parent of runtime type String
Exception in thread "main" java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer