Effective Java 的笔记,代码、英语原文为主,批注、翻译为辅。
Item 26: Don’t use raw types
请不要使用原始类型( raw types 实在不知道该怎么翻译🤷🏻♀️,中文版书籍译为原生态类型)
Should not use raw types
As mentioned throughout this book, it pays to discover errors as soon as possible after they are made, ideally at compile time.
Java 作为静态、强类型语言,最好在编译期间发现错误,写代码也倾向于:便于在编译期发现错误的代码,使用编译时信息协助排除大量运行时问题,越早发现错误越好。
As noted earlier, it is legal to use raw types (generic types without their type parameters), but you should never do it. If you use raw types, you lose all the safety and expressiveness benefits of generics.
如果使用 raw types ,就失去了泛型在安全性和描述性方面的所有优势。
While you shouldn’t use raw types such as List, it is fine to use types that are parameterized to allow insertion of arbitrary objects, such as
List<Object>
.
List
VS List<Object>
Just what is the difference between the raw type List
and the parameterized type List<Object>
?
Loosely speaking, the former has opted out of the generic type system, while the latter has explicitly told the compiler that it is capable of holding objects of any type. While you can pass a
List<String>
to a parameter of type List, you can’t pass it to a parameter of typeList<Object>
.
raw type List
: 逃避了泛型检查。
parameterized type List<Object>
: 明确告知编译器能够持有任意类型的对象。
List<String>
可以传递给 List
的参数,但不能传给 List<Object>
的参数。
There are
sub-typing
rules for generics, and List is a subtype of the raw type List, but not of the parameterized typeList<Object>
.As a consequence, you lose type safety if you use a raw type such as List, but not if you use a parameterized type such as
List<Object>
.
For example:
|
|
IntelliJ IDEA报错:
|
|
Covariant VS Invariant
Arrays are covariant. Generics are invariant.
数组是协变(covariant)的,泛型、集合是不变(invariant)的。
covariant:
This scary-sounding word means simply that if Sub is a subtype of Super, then the array type Sub[] is a subtype of the array type Super[].
invariant:
for any two distinct types Type1 and Type2,
List<Type1>
is neither a subtype nor a supertype ofList<Type2>
.
e.g. P=C —> P[ ]=C[ ]
不变的举例:
泛型的优点:
- 更好的安全性:编译期就发现错误,保证类型安全
- 更好的可读性:省去强制类型转换
Must use raw types
There are a few minor exceptions to the rule that you should not use raw types. You must use raw types in class literals. The specification does not permit the use of parameterized types (though it does permit array types and primitive types). In other words,
List.class, String[].class, and int.class
are all legal, butList<String>.class and List<?>.class
are not.
Summary
In summary, using raw types can lead to exceptions at runtime, so don’t use them. They are provided only for compatibility and interoperability with legacy code that predates the introduction of generics.
As a quick review,
Set<Object>
is a parameterized type representing a set that can contain objects of any type,Set<?>
is a wildcard type representing a set that can contain only objects of some unknown type, andSet
is a raw type, which opts out of the generic type system. The first two are safe, and the last is not.
For quick reference, the terms are summarized in the following table:
Term | Example |
---|---|
Parameterized type | List<String> |
Actual type Parameter | String |
Generic type | List<E> |
Formal type parameter | E |
Unbounded wildcard type | List<?> |
Raw type | List |
Bounded type parameter | <E extends Number> |
Recursive type bound | <T extends Comparable<T>> |
Bounded wildcard type | List<? extends Number> |
Generic method | static <E> List<E> asList(E[] a) |
Type token | String.class |