Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
java.lang.ClassException:无法将A转换为B_Java_Inheritance - Fatal编程技术网

java.lang.ClassException:无法将A转换为B

java.lang.ClassException:无法将A转换为B,java,inheritance,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(); } } 单独编译时,这两行代码都可以很好地编译,但会产生运行时错误 使用java.lang.ClassE

我实现了以下代码:

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不能转换为B

为什么它们编译得很好,但会出现运行时错误

A a1 = (B) new A();
因为
A
不是
B


编译时之所以有效,是因为您正在强制转换并明确保证编译器在运行时
A
B

这很简单。当您扩展时,您必须使用
是一个

B `is a` A
A `is not` B
一个更现实的例子

class Animal{
}

class Dog extends Animal{
}

class Cat extends Animal{
}
狗是一种动物 动物
不是必需的狗(例如:猫不是狗,猫是动物)


您将获得运行时异常,因为在运行时意识到该动物不是狗,这是调用
向下播放
,您试图做的事情不安全。

它本身暗示的
编译器的名称将只查看
表达式的编译时类型

它不对
表达式的运行时类型进行假设

真正的问题


不能将A转换为B。你可以将B转换为A。当你有了芒果,你就有了水果。但当你有了水果,并不意味着你就有了芒果。

我不确定编译部分,但我可以解释运行时错误

B扩展了A,这意味着B类的每个对象也是A类型的对象。反之则不成立


将A与“哺乳动物”比较,B与“奶牛”比较。母牛始终是哺乳动物,但并非所有哺乳动物都是母牛。

与铸造完成有关。您正在告诉编译器:“嘿,别担心,这就是我说的,如果您有问题,请在运行时与我联系。”


基本上,编译器是让你做你的事情。当您显式强制转换某些内容时,编译器不会执行检查。当您运行时,程序尝试强制转换但失败,这时您将看到错误。

当B扩展A时,意味着A的所有方法和属性也出现在B中

所以你可以把B投给A

但是你不能把A投给B


你必须真正关心应用程序中的强制转换。

事实上
B扩展了A
,这意味着
B
A
,也就是说,B类似于A,但可能会添加一些其他内容

相反是错误的<代码>A
不是
B
。因此,您不能将
A
转换为
B


这样想<代码>动物
动物
<代码>B
Bee
。蜜蜂是动物吗?是的。有蜜蜂吗?不是,不是。例如,狗是动物,但绝对不是蜜蜂。

它在运行时失败的原因是对象不是B。它是a。因此,虽然一些可以强制转换为B,但您的不能

编译器无法分析对象上发生的所有事情。比如说

A a1 = new B();
A a2 = new A();

B b1 = (B) a1;    // Ok
B b2 = (B) a2;    // Fails

所以编译器不确定你的A对象是否真的可以转换成B。所以在上面,它认为最后两行是可以的。但是当你实际运行程序时,它意识到
a2
不是一个B,它只是一个a.

,因为
a
B
的父项
B
扩展了
A
的功能,但保留了
A
的原始功能。因此
B
实际上可以转换为
A
,但反之亦然


如果
B
添加了一个新方法,比如说
newMethodInB()
,该怎么办。如果您试图通过实例
A
上的变量
B
调用该方法(假设强制转换成功),您会期望什么?当然,你肯定会得到一个错误,因为这个方法在
A

中不存在,当你说B扩展了A,A就成了B的父亲 现在从技术上讲,B具有A的所有特性以及它自己的 而A只有它自己的特点

如果你说把A转换成B并分配给B,那就可以了 但是如果你说将A转换成B并分配给A,那是不可能的,因为A不知道B中存在的额外字符。


这些事情都是在运行时发生的,所以它会给你一个运行时错误。

因为,编译器看到的只是a被转换成B。因为有些a实际上可以是B,这可能适用于那些a。通过编写显式转换,您可以确保这个特定的A实际上是一个有效的B。但是,事实并非如此

A justA = new A();
A anAThatIsAlsoAValidB = new B(); // implicit cast to supertype

B b1 = (A) anAThatIsAlsoAValidB ; // Cast an A into a B. At runtime, this will work fine! Compiler allows casting A into B.
B b2 = (A) justA; // Cast an A into a B. At runtime, this won't work. Compiler has/uses no more info than above.
以下是编译器不真正了解类型的原因:

com.example.ThridPartyType obj = new com.example.ThridPartyType();
B b = (B) obj.getSomeA(); 
// getSomeA() returns A and that is all the compiler knows.
// Depeding on the implementation of "ThridPartyType::getSomeA()" the A returned may or may not actually also be a valid B. 
// Hence, if the cast works or not will only be known at runtime. If it doesn't, the Exception is thrown.

下面是一个compiletime转换-

A a = new B();
这种静态转换是由编译器隐式执行的,因为编译器知道B是a

下面的代码无法编译-

B b = new A();
这里没有compiletime转换,因为编译器知道A不是B

以下汇编-

B b = (B) new A();
这是一个动态铸造。使用
(B)
可以明确地告诉编译器您希望在运行时进行转换。当运行时尝试执行强制转换,但发现无法执行,并抛出一个CCE时,您将在运行时获得一个CCE


当您执行(或必须执行)类似操作时,您(而不是编译器)有责任确保CCE不会在运行时发生。

类型
a
的变量可以存储对类型
a
的对象或其子类型的引用,如您的case类
B

因此,可以使用如下代码:

A a = new B();
变量
a
属于
a
类型,因此它只能访问该类的API,不能访问它所引用的类B中添加的方法。但有时我们希望能够访问这些方法,因此应该能够以某种方式将
a
中的引用存储在某种更精确类型的变量中(此处
BB b = a;//WRONG!!! "Type mismatch" error
B b = (B)a;
B b1 = (B) new A();
A a1 = (B) new 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();