我有一个简单的foo
类,并且能够强制转换为集合接口(Map
或List
)而没有任何编译器错误。
请注意,Foo
类不会实现任何接口或扩展任何其他类。
public class Foo {
public List<String> getCollectionCast() {
return (List<String>) this; // No compiler error
}
public Map<String, String> getCollection2Cast() {
return (Map<String, String>) this; // No compiler error
}
public Other getCast() {
return (Other)this; // Incompatible types. Cannot cast Foo to Other
}
public static class Other {
// Just for casting demo
}
}
当我尝试将Foo
类强制转换为集合时,为什么Java编译器不返回不兼容类型错误?
Foo
未实现Collection
。我不希望看到类型不兼容的错误,因为给定当前的Foo
类签名,所以它不能是Collection
。
答案 0 :(得分:125)
不是因为它们是集合类,而是因为它们是接口。 Foo
没有实现它们,但是可以实现其子类。因此,这不是编译时错误,因为这些方法可能对子类有效。在运行时,如果this
不是实现这些接口的类,那么自然是运行时错误。
如果将List<String>
更改为ArrayList<String>
,您也会收到编译时错误,因为Foo
子类可以实现List
,但可以请勿扩展ArrayList
(因为Foo
不扩展)。同样,如果您制作Foo
final
,则编译器会因接口强制转换而给您一个错误,因为它知道它们永远不会为真(因为Foo
不能有子类,并且不会没有实现这些接口)。
答案 1 :(得分:47)
除非可以确定无法建立关系,否则编译器不会阻止代码将类型强制转换为接口。
如果目标类型是接口,那么这是有道理的,因为扩展Foo
的类可以实现Map<String, String>
。但是,请注意,这仅适用于 Foo
而不是final
。如果您使用final class Foo
声明了自己的课程,则该转换将无效。
如果目标类型是类,则在这种情况下它只会失败(尝试(HashMap<String, String>) this
),因为编译器肯定知道Foo
和HashMap
之间的关系是不可能。
作为参考,这些规则在JLS-5.5.1中进行了描述(T =目标类型-Map<String, String>
,S =源类型-Foo
)
如果T [目标类型]是接口类型:
如果S不是最终类(第8.1.1节),那么,如果存在T的超类型X和S的超类型Y,使得X和Y都是可证明是不同的参数化类型,并且X和Y的擦除相同,则发生编译时错误。
< / li>
否则,强制转换在编译时始终合法(因为即使S不实现T,S的子类也可能会这样)。如果S是最终类(第8.1.1节),则S必须实现T,否则会发生编译时错误。
请注意带引号的文本中的 粗体 注释。
答案 2 :(得分:-6)