OO / Generics with Numbers

时间:2013-02-27 19:59:46

标签: java oop

我有这种情况,但为什么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 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分: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&lt; Number&gt;完全相同的列表。

doInsert(List<? super Number> myList)

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

答案 2 :(得分:0)

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

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);
    }
}

答案 3 :(得分: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
  }

}