Java泛型未经检查的强制转换 - 通配符边界

时间:2014-11-11 11:54:09

标签: java generics warnings

我试图理解泛型,但我阻止了通配符边界和强制转换。例如:

List<? extends Number> l = new ArrayList<>();
List<PositiveInteger> p = new ArrayList<PositiveInteger>();
p.add(new PositiveInteger(10));
l = p;
NegativeInteger ni = (NegativeInteger) l.get(0);// runtime java.lang.ClassCastException:
System.out.println(ni);

NegativeNumber和PositiveNumber都扩展了Number。所以问题是为什么在将列表中的元素转换为NegativeNumber时编译时没有警告?有没有办法防止这种类型的异常?

3 个答案:

答案 0 :(得分:0)

使用通配符(如<? extends Number>)定义Generic类型时,不应将对象强制转换为Number的子类,因为泛型类型表示您将获得Number的子类实例。与此代码块相似:

Number n = new PositiveInteger(10);
NegativeInteger  ni = (NegativeInteger ) n;

答案 1 :(得分:0)

一旦你投射,你告诉编译器“我知道我在做什么”,所以只要可以投射对象(NegativeNumber extends Number - &gt; ok)它就不会抱怨。

如果你真的需要强制转换(你想要避免;泛型是关于编译时安全性并避免“不安全”的强制转换),你可以先检查它:

Number number =  l.get(0);
if (number instanceof NegativeInteger){
    NegativeInteger ni = (NegativeInteger) l.get(0);
    ...
}

答案 2 :(得分:0)

好吧,如果你这样做会发生同样的事情:

Object a;
Integer b = new Integer(5);
a=b
Double c = (Double)a;

发生ClassCastException,因为您正在尝试将类转换为另一个不是父类/子类的类

关于防止它的问题:

编译器在运行时不知道l中的内容。但您可以使用List<PositiveInteger>而不是通配符来告诉编译器l中的内容。如果必须使用List<? extends Number>,则可以创建一个尝试强制转换对象的方法,这样就可以判断对象是List<PositiveInteger>还是List<NegativeInteger>,如here:< / p>

if(l instanceof List<NegativeInteger>){
   //Do something
}

所以如果我相应地更改你的代码:

List<? extends Number> l = new ArrayList<>();
List<PositiveInteger> p = new ArrayList<PositiveInteger>();
p.add(new PositiveInteger(10));
l = p;
Object ni = l.get(0);
if(ni instanceof NegativeInteger){
   NegativeInteger tmp = (NegativeInteger)ni;
   System.out.println(ni);
}