类型变量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;。所以为了安全起见,它不允许我们这样做。
那么我们应该怎么做才能将引用从ato分配B1?我们需要明确告诉编译器我们知道这里可能存在类型不匹配的问题,但我们确信a可以在 type 变量中安全地分配引用B。我们通过将value from转换a为 type Bvia来做到这一点(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;
这里的问题是您不能将对超类对象的引用存储在其派生类型的变量中。
为什么存在这样的限制?假设派生类添加了一些超类型没有的新方法
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。