集合复制功能如何在java中工作

时间:2014-08-18 14:41:25

标签: java generics

我试图了解Java Generic的工作原理。这是问题所在。

  public static void main(String args[]){

    List<Object> obj = Arrays.<Object>asList(23,"456",56.89);
    List<Integer> intb = new ArrayList<>();
    intb.add(234);
    intb.add(345);
    Collections.copy(obj,intb);
    for(Object d : obj){
        System.out.println(d);
    }

   }  

这样可以正常工作。但是我实现了我自己的复制功能

   public static <T> void copy(List<? super T> des,List<? extends T> scr){
    for(T f : scr){
        des.add(f);
    }
  }

然后我使用copy(obj,intb)而不是Collections.copy(obj,intb)。然后我收到错误。我不明白为什么,但我知道&#34;?扩展T&#34;表示任何类型的T和&#34;的子类型?超级T&#34;指任何类型为T的超类型。

3 个答案:

答案 0 :(得分:2)

您无法向此fixed-length list添加任何内容:

List<Object> obj = Arrays.<Object>asList(23,"456",56.89);

您只能为其元素设置新值(这是Collections.copy()所做的)。另请参阅Javadoc

  

返回由指定数组支持的固定大小的列表。

你可能打算这样做:

List<Object> obj = new ArrayList<>(Arrays.asList(23,"456",56.89));

答案 1 :(得分:1)

复制方法

public static <T> void copy(List<? super T> dest, List<? extends T> src) {
        int srcSize = src.size();
        if (srcSize > dest.size())
            throw new IndexOutOfBoundsException("Source does not fit in dest");

        if (srcSize < COPY_THRESHOLD ||
            (src instanceof RandomAccess && dest instanceof RandomAccess)) {
            for (int i=0; i<srcSize; i++)
                dest.set(i, src.get(i));
        } else {
            ListIterator<? super T> di=dest.listIterator();
            ListIterator<? extends T> si=src.listIterator();
            for (int i=0; i<srcSize; i++) {
                di.next();
                di.set(si.next());
            }
        }
    }

copy将值替换为索引0的索引。

 public static <T> void copy(List<? super T> des,List<? extends T> scr){
    for(T f : scr){
        des.add(f);
    }
  }

这种方法加入尾巴。

答案 2 :(得分:1)

嗯,有点晚了,但为什么你的编译器抱怨你的代码不仅仅是因为你在List方法中使用了固定大小(不可变)copy作为参数。

List<Object> obj = Arrays.<Object>asList(23, "456", 56.89);
Collections.copy(obj, intb);

这也是因为你的(copy)方法声明。

public static <T> void copy(List<? super T> des,List<? extends T> scr) {

上面的声明有两个带通配符的列表。使用通配符类型<?>时,会向编译器发出忽略类型信息的消息。无论何时将参数传递给泛型类型,java编译器都会尝试推断传递的参数的类型以及泛型的类型,并证明类型安全性的合理性。现在,(在您的复制方法中)您尝试使用add()方法在列表中插入元素。由于des(您的目标列表)不知道它所拥有的对象的确切类型,因此向其添加元素是有风险的。在该语言中引入了泛型,以确保首先确保类型安全。所以你不能使用像修改对象的add这样的方法。我希望copyjava.util.Collections方法的默认实现有助于澄清它。

public static <T> void copy(List<? super T> dest, List<? extends T> src) {
        int srcSize = src.size();
        if (srcSize > dest.size())
            throw new IndexOutOfBoundsException("Source does not fit in dest");

        if (srcSize < COPY_THRESHOLD ||
            (src instanceof RandomAccess && dest instanceof RandomAccess)) {
            for (int i=0; i<srcSize; i++)
                dest.set(i, src.get(i));
        } else {
            ListIterator<? super T> di=dest.listIterator();
            ListIterator<? extends T> si=src.listIterator();
            for (int i=0; i<srcSize; i++) {
                di.next();
                di.set(si.next());
            }
        }
    }

我知道已经存在相同的代码块,但没有解释为什么我们不能在add s上使用带有通配符的List等方法的原因,那就是主要是为了保护类型安全。