意外的类型安全违规

Mar*_*nik 44 java casting

在下面的代码中,对一个看似不兼容的类型的dowcast传递编译:

public class Item {
  List<Item> items() { return asList(new Item()); }
  Item m = (Item) items();
}
Run Code Online (Sandbox Code Playgroud)

Item并且List<Item>是完全不同的类型,因此演员阵容永远不会成功.为什么编译器允许这样做?

JB *_*zet 52

A List<Item>很可能是一个项目.参见例如:

public class Foo extends Item implements List<Item> {
    // implement required methods
}
Run Code Online (Sandbox Code Playgroud)

演员告诉编译器:"我知道你不能确定这是Item类型的对象,但我知道比你好,所以请编译".如果返回的对象不可能是Item的实例(例如,Integer不能是a String),编译器将只拒绝编译

在运行时,将检查方法返回的实际对象的类型,如果它实际上不是Item类型的对象,则会得到ClassCastException.

  • @EugeneStepanenkov`Integer`和`String`是*classes*,这就是你需要知道的全部内容:`Integer`的子类永远不能成为`String`,无论是最终还是不是. (5认同)
  • 所以基本上它编译是因为你可以扩展Item并使子类实现List <Item>.如果你使Item final,它就不再编译了. (4认同)
  • Integer和String是最终类;) (3认同)

Mak*_*oto 17

相关的规格条目可以在这里找到.设S为源,T为目标; 在这种情况下,源是接口,目标是非最终类型.

如果S是接口类型:

  • If T is an array type, then S must be the type java.io.Serializable or Cloneable (the only interfaces implemented by arrays), or a compile-time error occurs.

  • If T is a type that is not final (§8.1.1), then if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs.

    Otherwise, the cast is always legal at compile time (because even if T does not implement S, a subclass of T might).

It took a few readings to get this straight, but let's start from the top.

  • The target is not an array, so this rule doesn't apply.
  • Our target does not have a parameterized type associated with it, so this rule would not apply.
  • 这意味着演员在编译时总是合法的,由于JB Nizet所说明的原因:我们的目标类可能没有实现源,但是子类可能.

这也意味着如果我们按照这个片段转换到没有实现接口的final类,它将无法工作:

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