Java泛型内各种参数的异同(2)

界,即持有的对象只能为 Fruit 或 Fruit 的子类型。 相应地, List<? super Fruit> 则为 List 可以持有的对象类型规定了一个下界,即持有的对象只能为 Fruit 或 Fruit 的超类。

因此若将 test 方法改为下面这样,则 add 操作可以进行。

1    public void test(List<? super Fruit> list) {
2        list.add(new Fruit());
3        list.add(new Orange());
4        list.add(new Apple());
5    }   

因为我们可以确定 传入 test 方法的参数至少也是一个 持有 Fruit 类型的 List,所以我们向此 list 中加入 Fruit 及Fruit 的子类型的对象是没有任何问题的。

四、<? extends Fruit> 与 <T extends Fruit> 区别。

两个东西应用的场景是不同的,<T extends Fruit>作用于方法或者类上,而 <? extends Fruit> 则不可以。下面举例说明。

public class TestGen<T extends Fruit> {
    private T value;
   
    public TestGen(T value) {
        this.value = value;
    }
   
    public T getValue() {
        return value;
    }

public void setValue(T value) {
        this.value = value;
    }
   
    public <E extends Fruit> void test1(E e) {
        System.out.println(e.getClass().getName());
    }
   
    public static void main(String[] args) {
       
        TestGen<? extends Fruit> tg = new TestGen<Fruit>(new Fruit());
        //由于 setValue 方法参数列表中涉及通配符(setValue方法中的  T 相当于 ? extends Fruit),setValue方法不能调用。
        //tg.setValue(new Fruit());
       
        tg.test1(new Fruit());
        //tg.test1(new Object()); Object并不是Fruit的子类型,并不能作为参数传入test1方法。
    }
}

在代码中可以看到,类上的限定 <T extends Fruit> 及方法上的限定 <E extends Fruit> 使得类和方法能接受的类型均为 Fruit 及 Fruit 的子类型。

五、原生List 与 List<?> 区别。

无界通配符 ? 与 原生类型看似好像是等价的,但无界通配符可以有以下含义:“我是想用Java的泛型来编写这段代码,我在这里并不是要用原生类型,但是在当前这种情况下,泛型参数可以持有任何类型”。

使用无界通配符的  List<?> 要比 原生 List 要安全些。 在原生 list 中,我们可以随意进行插入操作,可以向同一个 list 中既插入 object 对象,又插入 Fruit,Apple 对象,而 List<?> 是不允许进行 add 操作的。

六、解释自限定泛型 class A<T extends A<T>>{ }。

在 Java 泛型中,这算是一种经常出现的惯用法,这种用法意味着 基类 (这里的类A) 使用其导出类代替其参数,泛型基类变成了一种其所有导出类的公共公能的模板,但是这些功能对于其所有参数和返回值,将使用导出类型。

下面举例说明。

class A <T extends A<T>> {
    void set(T arg) {
        System.out.println("in A");
    }
}
//泛型基类变成了一种其所有导出类的公共公能的模板
//导出类B和C均可调用基类的set方法,且只接受导出类对应的类型
class B extends A<B> {
   
}
class C extends A<C> {
   
}
public class TestGen {
    void test2(B b1, B b2, C c1, A a1) {
        b1.set(b2);
        //使用自限定泛型时,在导出类中调用的set方法只接受对应的导出类型,不接受基类型和其他的导出类型
        //b1.set(c1); 不接受其他的导出类型
        //b1.set(a1); 不接受基类型,编译器不能识别将类型传递给set的尝试,因为没有任何方法有这样的
        //签名,实际上,这个参数已经被覆盖
    }
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/d626154442925f9c128c0db6a20e7f11.html