为什么有必要在泛型通配符中进行读取和超级写入时进行扩展?

时间:2014-01-18 21:05:11

标签: java generics

我很难理解仿制外卡的概念。

根据我的理解<?>类型未知用于解决泛型中不支持的协方差,它应该适合任何类型的集合,<?extends T>表示您可以拥有类型集合{{ 1}}或扩展T的类意味着您可以拥有T.<?super T>类型的集合T或超级T

如果上述错误,请纠正我。

当我尝试这样写时:

import java.util.*;

public class Gclass {
    static Gclass t;

    public void write(List< ?super String > lw){
        lw.add("b");
    }

    public void read(List< ? extends String> lr){
        String s=lr.get(2);
        System.out.println(s);
    }

    public static void main(String[] args) {
        t=new Gclass();
        List<String> l=new ArrayList<String>();
        l.add("a");
        l.add("");
        System.out.println(l);
        t.write(l);
        System.out.println(l);
        t.read(l);
        System.out.println(l);
    }
}

它有效,但我怀疑的地方是:

  1. 根据我的理解,(extends和super)都包含声明的类型,因此在这种特殊情况下,我的List类型为String。我可以交换extends和super,但是我得到了编译错误?

  2. 如果写? super Object不起作用?它应该工作,因为它是String的超级

  3. 我没有检查读数,因为String无法扩展,但我想我在这里也错过了一个概念。

  4. 我已经阅读了与此问题相关的所有问题的答案,但我仍然无法对此有充分的了解。

3 个答案:

答案 0 :(得分:5)

String确实是一个不好的例子,因为它是一个final类,但请考虑使用Number之类的东西。

如果某个方法采用List<? extends Number>类型的参数,那么您可以将其传递给List<Number>List<Integer>List<BigDecimal>等。因此,在方法正文中,它是很好地接受列表的 out (因为你知道它们必须是Number的实例)但是你不能把放在中,因为你没有知道它是否安全(例如,编译器不能让你冒Integer放入List<Float>的风险。

相反,如果该方法需要List<? super Number>,那么您可以传递List<Number>List<Object> - 您无法从此列表中取出任何内容,因为您不知道它的类型是 * ,但你知道将Number 放在中肯定是安全的。

*从技术上讲,你可以解决问题,但你可以指定的唯一类型是Object

答案 1 :(得分:2)

  

根据我的理解,(extendssuper)包含声明的类型(此处为String),因此在此特定情况下,List类型为{ {1}} ...我可以交换Stringextends但我收到编译错误?

你是对的,super? extends String都包含? super String。但是你错过了String还包括? super StringCharSequence的观点,它不在Object的范围内。您可以向? extends String添加String,无论该列表的类型是什么,它都可以引用List<? super String>。但是,您无法向String添加Integer,因为该列表实际上可能是List<? extends Number>

  

如果写List<Float>不起作用?它应该工作,因为它是? super Object的超级?

StringObject的超类适合您String的位置,并使用? super String。因此,Object可以捕获? super String,但Object无法捕获? super Object,因为String不是String的超级类型。可以这样想:“实际类型取代Object,它必须满足?附带的规则。

答案 2 :(得分:1)

List<? super String>表示lw的值为List且类型参数为String或超类,因此您可以添加String值{ {1}}(因为它可以转换为list的类型参数)。

"b"表示List<? extends String>的值为lw,其类型参数为List或它的子类,因此来自String的值可以转换为lw