• Index

super通配符

Last updated: ... / Reads: 1999660 Edit

``````void set(Pair<Integer> p, Integer first, Integer last) {
p.setFirst(first);
p.setLast(last);
}
``````

`extends`通配符相反，这次，我们希望接受`Pair<Integer>`类型，以及`Pair<Number>``Pair<Object>`，因为`Number``Object``Integer`的父类，`setFirst(Number)``setFirst(Object)`实际上允许接受`Integer`类型。

``````void set(Pair<? super Integer> p, Integer first, Integer last) {
p.setFirst(first);
p.setLast(last);
}
``````

``````public class Main {
----
public static void main(String[] args) {
Pair<Number> p1 = new Pair<>(12.3, 4.56);
Pair<Integer> p2 = new Pair<>(123, 456);
setSame(p1, 100);
setSame(p2, 200);
System.out.println(p1.getFirst() + ", " + p1.getLast());
System.out.println(p2.getFirst() + ", " + p2.getLast());
}

static void setSame(Pair<? super Integer> p, Integer n) {
p.setFirst(n);
p.setLast(n);
}
----
}

class Pair<T> {
private T first;
private T last;

public Pair(T first, T last) {
this.first = first;
this.last = last;
}

public T getFirst() {
return first;
}
public T getLast() {
return last;
}
public void setFirst(T first) {
this.first = first;
}
public void setLast(T last) {
this.last = last;
}
}
``````

``````void setFirst(? super Integer);
``````

``````? super Integer getFirst();
``````

``````Integer x = p.getFirst();
``````

``````Object obj = p.getFirst();
``````

• 允许调用`set(? super Integer)`方法传入`Integer`的引用；

• 不允许调用`get()`方法获得`Integer`的引用。

对比extends和super通配符

• `<? extends T>`允许调用读方法`T get()`获取`T`的引用，但不允许调用写方法`set(T)`传入`T`的引用（传入`null`除外）；

• `<? super T>`允许调用写方法`set(T)`传入`T`的引用，但不允许调用读方法`T get()`获取`T`的引用（获取`Object`除外）。

``````public class Collections {
// 把src的每个元素复制到dest中:
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i=0; i<src.size(); i++) {
T t = src.get(i);
}
}
}
``````

• `copy()`方法内部不会读取`dest`，因为不能调用`dest.get()`来获取`T`的引用；

• `copy()`方法内部也不会修改`src`，因为不能调用`src.add(T)`

``````public class Collections {
// 把src的每个元素复制到dest中:
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
...
T t = dest.get(0); // compile error!
}
}
``````

``````// copy List<Integer> to List<Number> ok:
List<Number> numList = ...;
List<Integer> intList = ...;
Collections.copy(numList, intList);

// ERROR: cannot copy List<Number> to List<Integer>:
Collections.copy(intList, numList);
``````

PECS原则

``````public class Collections {
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i=0; i<src.size(); i++) {
T t = src.get(i); // src是producer
}
}
}
``````

无限定通配符

``````void sample(Pair<?> p) {
}
``````

• 不允许调用`set(T)`方法并传入引用（`null`除外）；
• 不允许调用`T get()`方法并获取`T`引用（只能获取`Object`引用）。

``````static boolean isNull(Pair<?> p) {
return p.getFirst() == null || p.getLast() == null;
}
``````

``````static <T> boolean isNull(Pair<T> p) {
return p.getFirst() == null || p.getLast() == null;
}
``````

`<?>`通配符有一个独特的特点，就是：`Pair<?>`是所有`Pair<T>`的超类：

``````public class Main {
----
public static void main(String[] args) {
Pair<Integer> p = new Pair<>(123, 456);
Pair<?> p2 = p; // 安全地向上转型
System.out.println(p2.getFirst() + ", " + p2.getLast());
}
----
}

class Pair<T> {
private T first;
private T last;

public Pair(T first, T last) {
this.first = first;
this.last = last;
}

public T getFirst() {
return first;
}
public T getLast() {
return last;
}
public void setFirst(T first) {
this.first = first;
}
public void setLast(T last) {
this.last = last;
}
}
``````

小结

• 方法内部可以调用传入`Integer`引用的方法，例如：`obj.setFirst(Integer n);`

• 方法内部无法调用获取`Integer`引用的方法（`Object`除外），例如：`Integer n = obj.getFirst();`