当前位置: 首页 > 面试题库 >

java.lang.ClassException:不能将A强制转换为B

段曦
2023-03-14
问题内容

我实现了以下代码:

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

为什么它们编译良好,但会给出运行时错误?


问题答案:

type变量A可以A像在case类中那样存储对类型或其子类型的对象的引用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;。因此,为了安全起见,我们不允许这样做。

所以,我们应该做些什么来分配基准从aB1?我们需要 明确
告诉编译器,这里我们意识到潜在的类型不匹配问题,但是我们确保a可以安全地将持有的引用分配给type变量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;

这里的问题是 您不能在其派生类型的变量中存储对超类对象的引用
为什么存在这种限制?可以说派生类添加了一些超类型不喜欢的新方法

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



 类似资料: