Java 为什么要列出<;超类>;对象是否可以强制转换为子类对象?

Java 为什么要列出<;超类>;对象是否可以强制转换为子类对象?,java,compiler-errors,Java,Compiler Errors,我发现,案例1和案例3可以无错误地编译,但是案例2。(子类B扩展了超类,它是抽象类) 我想知道的是,为什么案例1和案例3没有编译错误。 如果是JDK错误,为什么案例2不能通过强制转换检查 // case 1 List<SuperClassA> a = new ArrayList<>(); SubClassB b = (SubClassB) a; // case 2 List<Number> m = new ArrayList<>

我发现,案例1和案例3可以无错误地编译,但是案例2。(子类B扩展了超类,它是抽象类) 我想知道的是,为什么案例1和案例3没有编译错误。 如果是JDK错误,为什么案例2不能通过强制转换检查

// case 1        
List<SuperClassA> a = new ArrayList<>();
SubClassB b = (SubClassB) a; 

// case 2
List<Number> m = new ArrayList<>();
Long n = (Long) m; //Error:(xx,yy) java: incompatible types: java.util.List<java.lang.Number> cannot be converted to java.lang.Long

// case 3
List<Exception> e = new ArrayList<>();
RuntimeException d = (RuntimeException) e;
//案例1
列表a=新的ArrayList();
子类b=(子类b)a;
//案例2
列表m=新的ArrayList();
长n=(长)m//错误:(xx,yy)java:不兼容的类型:java.util.List无法转换为java.lang.Long
//案例3
列表e=新的ArrayList();
RuntimeException d=(RuntimeException)e;

在不安全强制转换的情况下,您会收到一条警告,因为编译器无法确定是否应该允许此强制转换。(在较旧的Java版本中,现在很难删除它,因此在没有警告的情况下允许它)

注意:
Long
是一个
最终的
类,它假设没有一个
Long
的子类可以进行此转换

您可以创建一个类,如

class MyException extends RuntimeException implements List<Exception> {
类MyException扩展RuntimeException实现列表{
这些是有效的代码行

List<Exception> e = new MyException();
RuntimeException d = (RuntimeException) e; // ok.
List e=new MyException();
RuntimeException d=(RuntimeException)e;//确定。

请注意,案例1和案例3在运行时都会失败


在编译时,编译器只有在语言规范这么说的情况下才会抱怨不兼容的强制转换。语言规范允许情况1和3,因为它们不会100%失败

就编译器而言,案例1不会100%失败,因为它认为
a
可以包含实现
List
的任何类型的实例。如果有
子类b
的子类实际实现
List
,如果
a
实际包含该子类的实例,该怎么办如果
子类b
?那么演员阵容就会成功

情况2也是如此。如果有一个子类
RuntimeException
实际实现了
List
,如果
e
实际包含
RuntimeException
子类的一个实例,那么强制转换就会成功

案例2显示了一个错误,因为
Long
final
。不可能有实现
List
的子类,因此它肯定会失败

这在规范的第1部分中有规定(斜体为相关位):

给定编译时引用类型S(源)和编译时引用类型T(目标),如果由于以下规则没有发生编译时错误,则存在从S到T的转换

如果S是接口类型:

  • 如果T是数组类型,那么S必须是
    java.io.Serializable
    Cloneable
    (实现的唯一接口 或发生编译时错误

  • 如果T是非
    final
    (§8.1.1)的类或接口类型,则如果存在T的超类型X和S的超类型Y,则 X和Y都是可证明不同的参数化类型,并且 如果X和Y的擦除相同,则会发生编译时错误

否则,强制转换在编译时总是合法的(因为即使 不实现S,T的子类可能)

  • 如果T是最终类类型,则:

    –如果S不是参数化类型或原始类型,则T必须实现S,否则会发生编译时错误


酷,谢谢你的帮助。(我已经更正了我的疑问词,这是编译错误而非例外)“编译器只有在100%确定转换会失败时才会抱怨不兼容的转换。”不完全是:
(Integer)(String)null
不会编译,但也不会失败(如
(Integer)(Object)(String)所示)空
)。