为什么Java允许你投射到一个集合中?

2022-08-31 15:03:30

我有一个简单的类,我能够转换为集合接口(或),而不会出现任何编译器错误。请注意,类不实现任何接口或扩展任何其他类。fooMapListFoo

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
    }

}

为什么当我尝试将类强制转换为集合时,Java 编译器不返回不兼容的类型错误Foo

Foo不实现 。我预计会出现不兼容的类型错误,因为给定当前的类签名,这不可能是.CollectionFooCollection


答案 1

这不是因为它们是集合类,而是因为它们是接口。 没有实现它们,但它的子类可以。因此,这不是编译时错误,因为这些方法可能对子类有效。在运行时,如果不是实现这些接口的类,则自然是运行时错误。Foothis

如果更改为 ,则也会收到编译器时错误,因为子类可以实现 ,但不能扩展(因为不能)。类似地,如果你做 ,编译器会给你一个接口转换的错误,因为它知道它们永远不可能是真的(因为不能有子类,也不实现这些接口)。List<String>ArrayList<String>FooListArrayListFooFoofinalFoo


答案 2

编译器不会阻止代码将类型强制转换为接口,除非它可以确定这种关系是不可能的。

如果目标类型是接口,则这是有道理的,因为类扩展可以实现 。但是,请注意,这仅适用于 Foo 不是最终结果。如果您使用 声明类,则该强制转换将不起作用。FooMap<String, String>final class Foo

如果目标类型是一个类,那么在这种情况下,它只会失败(try),因为编译器肯定知道 和 之间的关系是不可能的。(HashMap<String, String>) thisFooHashMap

作为参考,JLS-5.5.1 中描述了这些规则(T = 目标类型 - , S = 源类型 -Map<String, String>Foo)

如果 T [目标类型] 是接口类型:

  • 如果 S 不是最终类 (§8.1.1),则如果存在 T 的超类型 X 和 S 的超类型 Y,使得 X 和 Y 都是可证明不同的参数化类型,并且 X 和 Y 的擦除是相同的,则会发生编译时错误。
    否则,强制转换在编译时始终是合法的(因为即使 S 不实现 T,S 的子类也可能实现)。

  • 如果 S 是最终类 (§8.1.1),则 S 必须实现 T,否则会发生编译时错误。

请注意引用文本中的粗体斜体注释。