1. 泛型的使用

泛型接口和泛型类统称为泛型。原生类型是指在声明的时候不带有对应的类别,例如List这是一个泛型类。
每个泛型定义了一个原始类型( raw type),它是没有任何类型参数的泛型类型的名称。 例如,对应于List<E>的原始类型是List。 原始类型的行为就像所有的泛型类型信息都从类型声明中被清除一样。 它们的存在主要是为了与没有泛型之前的代码相兼容。
在泛型被添加到Java之前,这是一个典型的集合声明。 从Java 9开始,它仍然是合法的,但并不是典型的声明方式了:

  1. // Raw collection type - don't do this!
  2. // My stamp collection. Contains only Stamp instances.
  3. private final Collection stamps = ... ;
  4. // Erroneous insertion of coin into stamp collection
  5. stamps.add(new Coin( ... )); // Emits "unchecked call" warning
  6. // Raw iterator type - don't do this!
  7. for (Iterator i = stamps.iterator(); i.hasNext(); )
  8. Stamp stamp = (Stamp) i.next(); // Throws ClassCastException
  9. stamp.cancel();

上述代码由于是原生类型,在编译的时候会通过,知道进行类型转换,试图将Coin类型转换成Stamp类型的时候才会发现报错。这种错误很隐蔽,被发现的晚。如果使用泛型,在写代码的时候IDE就会提示类型不对,无法通过。
使用原始类型(没有类型参数的泛型)是合法的,但是你不应该这样做。 如果你使用原始类型,则会丧失泛型的所有安全性和表达上的优势,原生类型之所以还存在是为了兼容java5之前的版本。

使用原生类型因为擦除了类型,所以再添加元素的时候,任何类型都可以添加进去:

  1. import java.time.LocalDate;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. /**
  5. * @author: qujundong
  6. * @date: 2020/11/28 下午9:10
  7. * @description:
  8. */
  9. public class Test {
  10. public static void main(String[] args) {
  11. List list = new ArrayList();
  12. list.add("str123");
  13. list.add("str345");
  14. list.add(LocalDate.now());
  15. System.out.println(list);
  16. }
  17. }
  18. [str123, str345, 2020-11-28]

2. 原生类型和通配符的区别

原生类型List和通配符List<?>都可以进行遍历list,但是通配符更安全,因为无法向list中添加除了null以外的其他元素。
但是有要使用原生类型而不是通配符的telling:

  1. 你必须在类字面值(class literals)中使用原始类型。 规范中不允许使用参数化类型(尽管它允许数组类型和基本类型)。 换句话说,List.classString [] .classint.class都是合法的,但List <String> .classList <?>.class不是合法的。
  2. 规则的第二个例外涉及instanceof操作符。 因为泛型类型信息在运行时被删除,所以在无限制通配符类型以外的参数化类型上使用instanceof运算符是非法的。 使用无限制通配符类型代替原始类型不会以任何方式影响instanceof运算符的行为。 在这种情况下,尖括号和问号就显得多余。 以下是使用泛型类型的instanceof运算符的首选方法: ```java // Legitimate use of raw type - instanceof operator if (o instanceof Set) { // Raw type Set<?> s = (Set<?>) o; // Wildcard type … }

`` 请注意,一旦确定o对象是一个Set,则必须将其转换为通配符Set <?>`,而不是原始类型Set。 这是一个强制转换,所以不会导致编译器警告。

总之,使用原始类型可能导致运行时异常,所以不要使用它们。 它们仅用于与泛型引入之前的传统代码的兼容性和互操作性。 作为一个快速回顾,Set<Object>是一个参数化类型,表示一个可以包含任何类型对象的集合,Set<?>是一个通配符类型,表示一个只能包含某些未知类型对象的集合,Set是一个原始类型,它不在泛型类型系统之列。 前两个类型是安全的,最后一个不是。