我想知道具体允许将一个类的对象作为另一个类进行转换。查看Class.isInstance(Object obj)javadoc,它表明对象必须与...分配兼容'与另一个类,以便投射到该类。但是什么构成'赋值兼容'?
我试图找出以下内容如何返回ClassCastException:
public class A
{
multiple private attributes
No constructor
multiple public methods
}
public class B extends A
{
blank default constructor
2 additional private attributes
4 additional public getter / setter methods for these attributes
}
该行
B b = (B)variable.getA() // where getA() returned an instance of class A
返回ClassCastException A不能转换为B.我知道从父类转换为子类是个坏主意。我没有编写有问题的代码,我只是在生产支持能力中查看它。
B类是代码库中唯一一个从A扩展的类。因此getA()的结果不是A的另一个子类(比如C)的对象,它被转换为A.
那么为什么在这种情况下Java不会将类A的对象强制转换为看似兼容的类B?
答案 0 :(得分:2)
考虑以下两种情况:
A a = new B();
B b = (B)a; <-- Ok.
A a = new A();
B b = (B)a; <-- ClassCastException
因此,为了将对象强制转换为B,它必须是B的实例(或B的子类)。
在你的情况下,它是A的实例。
答案 1 :(得分:1)
Class.isInstance(Object obj)的javadoc给出了assignment compatible
:
具体来说,如果此Class对象表示声明的类,则如果指定的Object参数是所表示的类(或其任何子类)的实例,则此方法返回true ;否则返回false。如果此Class对象表示数组类,则如果可以通过标识转换或扩展引用转换将指定的Object参数转换为数组类的对象,则此方法返回true;否则返回false。 如果此Class对象表示接口,则如果指定Object参数的类或任何超类实现此接口,则此方法返回true ;否则返回false。如果此Class对象表示基本类型,则此方法返回false。
基本上,如果类型A扩展或实现类型B,则可以将类型A的对象分配给类型B的变量。
答案 2 :(得分:0)
抛出以指示代码已尝试将对象强制转换为不是实例的子类。例如,以下代码生成ClassCastException
:
Object x = new Integer(0);
System.out.println((String)x);
答案 3 :(得分:0)
如果我们用有意义的名字替换A和B来帮助我们思考问题,那么答案就会变得更加清晰。如果A成为哺乳动物而B是狗,那么我们可以合理地说所有狗都是哺乳动物,但我们不能说所有的哺乳动物都是狗。即使他们表面上共享相同的属性,也不能保证所有哺乳动物都能履行作为狗的合同,编译器不应该尝试这样做。
答案 4 :(得分:0)
只想添加官方规范以支持 Ricardo's correct answer“如果类型A扩展或实现类型B,则可以将类型A的对象分配给类型B的变量”:
JLS定义分配兼容性如下:
如果可以通过赋值转换将表达式的类型转换为变量的类型,那么我们说表达式(或其值)可以分配给变量,或者等效地,表达式的类型可以与赋值兼容变量的类型。
“评估转换” 一词仅被定义为应用“任务上下文”一章中给出的列表中的适当转换:
术语“转换”还用于描述特定上下文中允许的任何转换,而没有具体说明。例如,我们说作为局部变量的初始化程序的表达式要进行“赋值转换”,这意味着将根据赋值上下文的规则为该表达式隐式选择特定的转换。
与引用类型最相关的是
5.1.5. Widening Reference Conversion
存在从任何引用类型S到任何引用类型T的扩展引用转换,条件是S是T的子类型(第4.10节)。
子类型包括已实现的接口(请参见4.10.2. Subtyping among Class and Interface Types )。
对于数字和泛型类型,还有其他规则,但它们与问题中给出的示例无关。