Java--通配符类型

上一篇:泛型的约束和局限性

Java有三种通配符限定:子类型限定通配符、超类型限定通配符、无类型通配符。

在泛型程序设计语法中,考察了下面的Pair泛型类,也提到了泛型的继承规则。无论S与T是什么关系,Pair<S>和Pair<T>没有任何关系。但当我们有这方面的需求时,就可以使用通配符类型。

public class Pair<T>{
    private T first;
    private T second;
    
    public T getFirst(){ return first; }
    public T getSecond(){ return second; }

    public void setFirst(T newVal){ first = newVal; }
    public void setSecond(T newVal){ second = newVal; }
}

通配符类型中,允许类型参数变化。

1、子类型限定通配符

Pair<? extends Employee>

表示任何Pair泛型类型,它的参数是Employee的子类。比如如果Manager是Employee的子类,那么Pair<Manager>是Pair<? extends Employee>的子类型。

注意:子类型限定通配符可以从泛型类读取,但不能向泛型类写入。用Pair泛型类举例,上面的setFirst()方法和getFirst()方法应该是下面这样:

? extends Employee getFirst()    //子类型限定下的getFirst方法
void setFirst(? extends Employee)    //子类型限定下的setFirst方法

因为上溯造型,无论是什么子类型,都可以上溯造型为Employee, 所以我们可以调用getFirst方法进行读取;但setFirst方法不行,编译器只知道需要Employee的一个子类型,但不知道具体类型。它拒绝传递任何特定的类型,毕竟?不能用来匹配。

2、超类型限定通配符

Pair<? super Manager>

这个通配符限制为Manager的所有超类型。带有超类型的通配符可以向泛型对象写入,但不能从泛型对象读取。

void setFirst(? super Manager)
? super Manager getFirst()   

上面不是真正的Java语法,但可以了解编译器知道什么。我们可以调用setManager方法,并传入Manager对象或者它的子类型对象,但不能传入Manager的超类;另外,调用getFirst方法不能保证返回对象的类型。只能把它赋给一个Object。

直观的讲,带有超类型限定的通配符可以向泛型对象写入,带有子类型限定的通配符可以从泛型对象读取。

3、无限定通配符

Pair<?>

类型Pair<?>的两个方法可以看作:

? getFirst()
void setFirst(?)

getFirst()的返回值只能赋给一个Object。setFirst()方法不能被调用,甚至不能被Object调用。不过可以调用setFirst(null)。

Pair<?>和Pair本质区别:可以用任意Object对象调用原始类型的setObject方法(涉及到类型擦除问题)。

通配符捕获:

例如我们要写一个交换方法,交换的时候必须临时保存第一个元素,但通配符不是类型变量,因此不能像下面这样写:

public static void swap(Pair<?> p){
    ? t = p.getFirst();  //Error
    p.setFirst(p.getSecond);
    p.setSecond(t);
}

上面这种方法不可取,但我们可以通过引入一个辅助方法来实现:

public static <T> void swapHelper(Pair<T> p){
    T t = p.getFirst();
     p.setFirst(p.getSecond);
    p.setSecond(t);
}

注意,swapHelper是一个泛型方法,但swap不是,swap具有固定的Pair<?>类型的参数。现在可以通过swap调用swapHelper:

public static void swap(Pair<?> p){ swapHelper(P); }

猜你喜欢

转载自my.oschina.net/HuoQibin/blog/1622119