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();