意外的类型安全违规
Unexpected type safety violation
在下面的代码中,对明显不兼容类型的向下转换通过了编译:
public class Item {
List<Item> items() { return asList(new Item()); }
Item m = (Item) items();
}
Item
和 List<Item>
是不同的类型,因此转换永远不会成功。为什么编译器允许这样做?
一个 List<Item>
很可能是一个项目。参见示例:
public class Foo extends Item implements List<Item> {
// implement required methods
}
强制转换告诉编译器:"I know you can't be sure that this is a object of type Item, but I know better than you, so please compile"。如果返回的对象不可能是 Item 的实例(例如,Integer
永远不可能是 String
),编译器只会拒绝编译它
在运行时,将检查该方法返回的实际对象的类型,如果它实际上不是 Item 类型的对象,您将得到一个 ClassCastException。
相关规范条目can be found here。设 S 为源,T 为目标;在这种情况下,源是接口,目标是非最终类型。
If S is an interface type:
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).
读了几遍才明白这一点,但让我们从头开始。
- 目标不是数组,因此此规则不适用。
- 我们的目标没有与之关联的参数化类型,因此此规则不适用。
- 这意味着转换在编译时总是合法的,原因由 JB Nizet 说明:我们的目标 class 可能没有实现源代码,但是子 class 可能.
这也意味着如果我们强制转换为未实现该接口的最终 class,它将无法工作,根据此代码段:
If S is not a parameterized type or a raw type, then T must implement S, or a compile-time error occurs.
在下面的代码中,对明显不兼容类型的向下转换通过了编译:
public class Item {
List<Item> items() { return asList(new Item()); }
Item m = (Item) items();
}
Item
和 List<Item>
是不同的类型,因此转换永远不会成功。为什么编译器允许这样做?
一个 List<Item>
很可能是一个项目。参见示例:
public class Foo extends Item implements List<Item> {
// implement required methods
}
强制转换告诉编译器:"I know you can't be sure that this is a object of type Item, but I know better than you, so please compile"。如果返回的对象不可能是 Item 的实例(例如,Integer
永远不可能是 String
),编译器只会拒绝编译它
在运行时,将检查该方法返回的实际对象的类型,如果它实际上不是 Item 类型的对象,您将得到一个 ClassCastException。
相关规范条目can be found here。设 S 为源,T 为目标;在这种情况下,源是接口,目标是非最终类型。
If S is an interface type:
If T is an array type, then S must be the type
java.io.Serializable
orCloneable
(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).
读了几遍才明白这一点,但让我们从头开始。
- 目标不是数组,因此此规则不适用。
- 我们的目标没有与之关联的参数化类型,因此此规则不适用。
- 这意味着转换在编译时总是合法的,原因由 JB Nizet 说明:我们的目标 class 可能没有实现源代码,但是子 class 可能.
这也意味着如果我们强制转换为未实现该接口的最终 class,它将无法工作,根据此代码段:
If S is not a parameterized type or a raw type, then T must implement S, or a compile-time error occurs.