我实现了这段代码:
class A {
//some code
}
class B extends A {
// some code
}
class C {
public static void main(String []args)
{
B b1 = (B) new A();
A a1 = (B) new A();
}
}
Run Code Online (Sandbox Code Playgroud)
这两行在单独编译时编译正常,但是给出了运行时错误java.lang.ClassException: A cannot be cast into B
.
为什么他们编译好,但给出运行时错误?
您需要了解在类型引用下A
可以存储任何A
扩展的类或类的对象B
,就像您的情况一样a
.
所以有可能
A a = new B();
Run Code Online (Sandbox Code Playgroud)
由于A
引用下的对象是类的实例,a
因此应该可以以某种方式将其存储在更准确的引用中,例如B
.所以让我们尝试这种方式:
B b = a;//WRONG!!! "Type mismatch" error
Run Code Online (Sandbox Code Playgroud)
这样的代码给我们编译时Type mismatch
错误,以防止这种情况:
让我们说
class B1 extends A
和 class B2 extends A
我们创造了A a = new B1();
.现在,如果编译器不会抛出B1 b = a;
错误,a
它也应该允许B1 b = a;
但是在其B2 b = a;
下面的实例a
与之无关B1
.
为了告诉编译器我们知道潜在的类型不匹配,我们需要明确地使用强制转换为我们想要的类
B b = (B)a;
Run Code Online (Sandbox Code Playgroud)
这就是为什么在编译时可以引用a
类的引用B
.
在您的代码中
B b1 = (B) new A();
A a1 = (B) new A();
Run Code Online (Sandbox Code Playgroud)
你需要知道,a
运营商返回了创建的对象相同类型的引用,以便B
将返回类型的引用(B)a
使
B b1 = (B) new A();
Run Code Online (Sandbox Code Playgroud)
实际上是一样的
A tmp = new A();
B b1 = (B) tmp;
Run Code Online (Sandbox Code Playgroud)
这里的问题是你不能存储某个类的对象来引用它的派生类.为什么?如果该派生类具有该对象类不具有的新方法,该怎么办?
class A {
// some code
}
class B extends A {
private int i;
public void setI(int i){
this.i=i;
}
}
Run Code Online (Sandbox Code Playgroud)
之后
B b = (B)new A();
Run Code Online (Sandbox Code Playgroud)
你会试着调用new
吗?会有可能吗?不,因为类A的实例没有方法new A()
,即使id有,它也没有A
在此方法中使用的字段.
这就是b.setI(42);
抛出的原因setI
.
它在运行时失败的原因是该对象不是B.它是A.所以虽然一些 As可以被转换为B,但是你的不能.
编译器无法分析发生在A对象上的所有事情.例如.
A a1 = new B();
A a2 = new A();
B b1 = (B) a1; // Ok
B b2 = (B) a2; // Fails
Run Code Online (Sandbox Code Playgroud)
所以编译器不确定你的A对象是否实际上可以转换为B.所以在上面,它会认为最后2行是正常的.但是当你真正运行程序时,它意识到这a2
不是B,它只是一个A.