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

Ozi*_*zil 12 java inheritance

我实现了这段代码:

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.

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

Psh*_*emo 9

您需要了解在类型引用下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.


Sno*_*irl 7

它在运行时失败的原因是该对象不是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.