标签:ram 适合 应该 类对象 返回值 使用 stat 需要 安全
使用通配符的原因:Java中的数组是协变的,但是泛型不支持协变。
首先了解下什么是数组的协变,看下面的例子:
Number[] nums = new Integer[10]; // OK
因为Integer是Number的子类,一个Integer对象也是一个Number对象,所以一个Integer的数组也是一个Number的数组,这就是数组的协变。
Java把数组设计成协变的,在一定程度上是有缺陷的。因为尽管把Integer[]赋值给Number[],Integer[]可以向上转型为Number[],但是数据元素的实际类型是Integer,只能向数组中放入Integer或者Integer的子类。如果向数组中放入Number对象或者Number其他子类的对象,对于编译器来说也是可以通过编译的。但是运行时JVM能够知道数组元素的实际类型是Integer,当其它对象加入数组是就会抛出异常(java.lang.ArrayStoreException)。
泛型的设计目的之一就是保证了类型安全,让这种运行时期的错误在编译期就能发现,所以泛型是不支持协变的。例如:
List<Number> nums = new ArrayList<Integer>(); // incompatible types
当确实需要建立这种向上转型的类型关系的时候,就需要用到泛型的通配符特性了。例如:
List<? extends Number> nums = new ArrayList<Integer>(); // OK
class-name<?> var-name
public static void print(List<?> list) {
for (Object obj : list) {
System.out.println(o);
}
}
为什么要使用这样脆弱的类型?它对于许多简单的操作非常有用。例如 ,下面这个方法将用来测试一个 pair 是否包含一个 mill 引用,它不需要实际的类型。 public static boolean hasNulls (Pair<?> p) { return p.getFirstO = null | | p.getSecondO = null ; } 通过将 hasNulls 转换成泛型方法,可以避免使用通配符类型: public static <T> boolean hasNulls (Pair<T> p) 但是,带有通配符的版本可读性更强。
class-name<? extends superclass> var-name
public static double sum(List<? extends Number> list) {
double s = 0.0;
for (Number num : list) {
s += num.doubleValue();
}
return s;
}
List<? extends Number> list = new ArrayList<Integer>(); // OK
List<? extends Number> list = new ArrayList<Object>(); // error
list.add(new Integer(1)); // error
list.add(null); // OK
Number n = list.get(0); // OK
Integer i = list.get(0); // error
public E get(int index) // 可以调用
public int indexOf(Object o) // 可以调用
public boolean add(E e) // 不能调用
class-name<? super subclass> var-name
public static void writeTo(List<? super Integer> list) {
// ...
}
List<? super Number> list = new ArrayList<Number>(); // OK
List<? super Number> list = new ArrayList<Object>(); // OK
List<? super Number> list = new ArrayList<Integer>(); // error
list.add(new Integer(1)); // OK
list.add(new Object()); // error
Object obj = list.get(0); // OK
Integer i = list.get(0); // error
从上面上边界限定的通配符和下边界限定的通配符的特性,可以知道:
简而言之,上边界限定(extends)的通配符适合于内容的获取,而下边界限定(super)的通配符更适合于内容的存入。所以就有了一个PECS原则来很好的解释这两种通配符的使用原则。
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i = 0; i < src.size(); i++) {
dest.set(i, src.get(i));
}
}
标签:ram 适合 应该 类对象 返回值 使用 stat 需要 安全
原文地址:https://www.cnblogs.com/everest33Tong/p/11588373.html