2

我有这种情况,但为什么 java 不尊重类层次结构?

import ...

public class GenericsTest {

    public static void main(String[] args) {
        List<Integer> myList = new ArrayList<Integer>();
        myList.add(1);
        myList.add(new Integer(2));
        new GenericsTest().doInsert(myList);
    }

    private void doInsert(List<? extends Number> myList) { // Number <- Integer
        myList.add(new Integer(1)); // This don't compiles
    }
}

有人可以解释一下吗?谢谢!!!

4

4 回答 4

2

泛型中的通配符并不意味着“任何事情”,而是意味着“我不知道”。所以List<? extends Number>不是“一个可以容纳任何扩展数字的列表”。它是“扩展数字的东西的列表,但我不知道它们是什么”。所以向它添加一个 Integer 是非法的,因为你不知道 Integer 是否是扩展这个列表的数字的东西。任何扩展 Number 的列表只是List<Number>.

于 2013-02-27T20:06:20.657 回答
1

想象一下,如果您提供的代码是合法的,那么下面的代码会发生什么:

List<Double> listDouble = new ArrayList<Double>();
doInsert(listDouble);

Double d = listDouble.get(0); //ClassCastException!

编译器在最后一行添加了一个隐式转换。这种转换在运行时失败,这破坏了泛型的类型安全保证,因为编译器并没有使您免于破坏列表内容和数据类型假设。它应该只保存 Double 值,但在里面找到了一个整数。

您的选择:

doInsert(List<? extends Number> myList)

允许迭代 Numbers,但不能添加到集合中。接受在 Number 的任何子类型上定义的列表。

doInsert(List<Number> myList)

允许迭代和修改,但只接受完全定义为 List<Number> 的列表。

doInsert(List<? super Number> myList)

允许迭代项目(作为对象),并允许添加任何类型的数字。仅接受其祖先数量的列表(在这种情况下它实际上无用)。

于 2013-02-27T20:09:03.197 回答
0

这不起作用的原因是被引用列表的类型不必是整数。但是,以下将编译。

private void doInsert(List<Number> myList) { 
    myList.add(new Integer(1));
}

随着:

private void doInsert(List<? extends Number> myList) { 
    ((List<Number>)myList).add(new Integer(1));
}  

我根据@Eyal Schneider 的评论附加了这个答案,以表明如果您正确设置,列出的第二种方式确实有效。尽管这很可能不是一件好事。

public class Test{  
    public void doInsert(List<? extends Number> myList) { 
        ((List<Number>)myList).add(new Integer(1));
        ((List<Number>)myList).add(new Short("2"));
        ((List<Number>)myList).add(new BigDecimal("3"));
        ...
    }  

    public static void main(String[] args){
        Test t=new Test();
        List<Number> list=new ArrayList<Number>();
        t.doInsert(list);
            for(Number number:list)
                System.out.println(number);
    }
}
于 2013-02-27T20:10:38.023 回答
0

考虑以下反例,假设它是可以接受的:

public class GenericsTest {
  public static void main(String[] args) {
    List<Integer> myList = new ArrayList<Integer>();
    myList.add(1);
    myList.add(new Integer(2));

    List<Integer> myDoubleList = new ArrayList<Double>();
    myList.add(1.0);
    myList.add(new Double(2));
    new GenericsTest().doInsert(myList); // Here you're trying to add an Integer into a List<Double>
  }

  private void doInsert(List<? extends Number> myList) { // Number <- Integer
    myList.add(new Integer(1)); // This don't compiles
  }

}
于 2013-02-27T20:15:45.157 回答