我实现了以下代码:
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();
}
}
当单独编译时,这两行都可以正常编译,但会导致运行时错误
与
java.lang.ClassException: A cannot be cast into B
。为什么它们编译良好,却给出运行时错误?
最佳答案
类型A
的变量可以存储对A
类型的对象或其子类型的引用,例如在您的案例类B
中。
因此,可能会有类似以下的代码:
A a = new B();
变量
a
的类型为A
,因此它只能访问该类的API,而不能访问在类B中添加的方法(即它引用的对象)。但是有时我们希望能够访问这些方法,因此应该可以将a
中的引用存储在更准确类型的某个变量(此处为B
)中,通过该变量我们可以访问类B中的其他方法。但是我们该怎么做?
让我们尝试通过以下方式实现它:
B b = a;//WRONG!!! "Type mismatch" error
这样的代码会导致编译时出现
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
?我们需要在此明确告知编译器我们知道潜在的类型不匹配问题,但是我们确保可以将a
中保存的引用安全地分配给B
类型的变量。我们通过将值从a
转换为通过B
键入(B)a
来实现。B b = (B)a;
但是让我们回到您的问题的例子
B b1 = (B) new A();
A a1 = (B) new A();
new
运算符返回与创建对象相同类型的引用,因此new A()
返回A
类型的引用,因此B b1 = (B) new A();
可以看作是
A tmp = new A();
B b1 = (B) tmp;
这里的问题是您不能在其派生类型的变量中存储对父类(super class)对象的引用。
为什么存在这种限制?可以说派生类添加了一些父类(super class)型不喜欢的新方法
class A {
// some code
}
class B extends A {
private int i;
public void setI(int i){
this.i=i;
}
}
如果允许的话
B b = (B)new A();
您以后可能会调用
b.setI(42);
结束。但这是正确的吗?否,因为类A的实例没有方法setI
,也没有该方法使用的字段i
。因此,为了防止这种情况,
(B)new A();
在运行时会抛出java.lang.ClassCastException
。关于java - java.lang.ClassException : A cannot be cast into B,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17217965/