当代码尝试将 Tree 向下转型为 Redwood 时,将抛出 ClassCastException
ClassCastException will be thrown when the code attempts to downcast a Tree to a Redwood
在下面的代码中,在第 7 行将 Tree 向下转换为 Redwood 时没有错误,但是为什么在将 Tree 向下转换为 Redwood 时在第 10 行出现运行时错误
public class Redwood extends Tree {
public static void main(String[] args) {
new Redwood().go();
}
void go() {
go2(new Tree(), new Redwood());
go2((Redwood) new Tree(), new Redwood());// no error here
}
void go2(Tree t1, Redwood r1) {
Redwood r2 = (Redwood)t1;// runtime error here
Tree t2 = (Tree)r1;
}
}
class Tree { }
嗯,虽然 Redwood
实例始终是 Tree
实例,但并非所有 Tree
实例都是 Redwood
。当你创建一个 Tree
实例(带有 new Tree()
)时,它肯定不是一个 Redwood
实例,并且不能转换为 Redwood
.
当 t1
不是 Redwood
时,Redwood r2 = (Redwood)t1;
抛出 ClassCastException
。在第一次调用 go2
时,第一个参数是 new Tree()
,它不是 Redwood
.
哦,你在这里看到错误的原因 - Redwood r2 = (Redwood)t1;
(第 10 行)而不是第 7 行(go2((Redwood) new Tree(), new Redwood());
)是第 10 行首先执行,在第一次调用go2()
(第 6 行)。如果注释第 6 行,则会在第 7 行出现异常。
您不能将 Tree
类型的对象转换为 Redwood
,因为它不是那种类型。如果父类型的变量实际上是作为该子类型创建的,则只能将其转换为其中一个子类型。
这是合法的,例如:
Tree t = new Redwood();
((Redwood)t).someMethod();
但是你不能转换父类型的对象,所以你这样做是不可能的:
Tree t = new Tree();
((Redwood)t).someMethod();
对象不是基于Redwood
的预留内存,也不是构造为一个,所以不可能突然是一个。
由于转换在某些情况下是合法的,编译器将允许它。在 运行 时,当从第 6 行调用它时,您将 运行 首先进入第 10 行的问题,因为逐行调试会显示。
编译器可能足够聪明,可以在编译时告知第 7 行永远不会工作,但它没有实现。
在第 7 行你只是传递了参数,实际的赋值是在第 9 行完成的,相当于下面的代码:
Tree T1= (Redwood)new Tree(); // 这很好,因为 base class 可以保存 derive class 的对象以及 base class。但是在第 10 行中,你将 T1 分配给 R2,其中 T1 实际上持有基 class 的对象,你试图将其强行分配给 Redwood 引用(通过强制转换),java 不允许这样做,就好像您将从这个 R2 引用调用 Redwood class(不在 Tree 中)的方法,而不是它无法调用,因为它实际上包含基础 class 对象。因此 class强制转换异常。
好的,这里是一个简化版本的解释,帮助我理解了整个事情:
规则是:这将起作用:
- 父 p = new 子 ();
- 子c = new Child();
但这行不通:
- 子 c = new Parent();
在下面的代码中,在第 7 行将 Tree 向下转换为 Redwood 时没有错误,但是为什么在将 Tree 向下转换为 Redwood 时在第 10 行出现运行时错误
public class Redwood extends Tree {
public static void main(String[] args) {
new Redwood().go();
}
void go() {
go2(new Tree(), new Redwood());
go2((Redwood) new Tree(), new Redwood());// no error here
}
void go2(Tree t1, Redwood r1) {
Redwood r2 = (Redwood)t1;// runtime error here
Tree t2 = (Tree)r1;
}
}
class Tree { }
嗯,虽然 Redwood
实例始终是 Tree
实例,但并非所有 Tree
实例都是 Redwood
。当你创建一个 Tree
实例(带有 new Tree()
)时,它肯定不是一个 Redwood
实例,并且不能转换为 Redwood
.
t1
不是 Redwood
时,Redwood r2 = (Redwood)t1;
抛出 ClassCastException
。在第一次调用 go2
时,第一个参数是 new Tree()
,它不是 Redwood
.
哦,你在这里看到错误的原因 - Redwood r2 = (Redwood)t1;
(第 10 行)而不是第 7 行(go2((Redwood) new Tree(), new Redwood());
)是第 10 行首先执行,在第一次调用go2()
(第 6 行)。如果注释第 6 行,则会在第 7 行出现异常。
您不能将 Tree
类型的对象转换为 Redwood
,因为它不是那种类型。如果父类型的变量实际上是作为该子类型创建的,则只能将其转换为其中一个子类型。
这是合法的,例如:
Tree t = new Redwood();
((Redwood)t).someMethod();
但是你不能转换父类型的对象,所以你这样做是不可能的:
Tree t = new Tree();
((Redwood)t).someMethod();
对象不是基于Redwood
的预留内存,也不是构造为一个,所以不可能突然是一个。
由于转换在某些情况下是合法的,编译器将允许它。在 运行 时,当从第 6 行调用它时,您将 运行 首先进入第 10 行的问题,因为逐行调试会显示。
编译器可能足够聪明,可以在编译时告知第 7 行永远不会工作,但它没有实现。
在第 7 行你只是传递了参数,实际的赋值是在第 9 行完成的,相当于下面的代码: Tree T1= (Redwood)new Tree(); // 这很好,因为 base class 可以保存 derive class 的对象以及 base class。但是在第 10 行中,你将 T1 分配给 R2,其中 T1 实际上持有基 class 的对象,你试图将其强行分配给 Redwood 引用(通过强制转换),java 不允许这样做,就好像您将从这个 R2 引用调用 Redwood class(不在 Tree 中)的方法,而不是它无法调用,因为它实际上包含基础 class 对象。因此 class强制转换异常。
好的,这里是一个简化版本的解释,帮助我理解了整个事情: 规则是:这将起作用:
- 父 p = new 子 ();
- 子c = new Child();
但这行不通:
- 子 c = new Parent();