泛型通配符:将超类对象分配给子类对象列表

时间:2013-03-06 19:11:01

标签: java generics

Question_1

class A {}
class B extends A {}

A aObj = new A();
B bObj = new B();

我们知道以下将导致运行时的类强制转换异常。

List<B> list_B = new ArrayList<B>();
list_B.add((B)aObj); //ClassCast exception

但是

List<? extends A> list_4__A_AND_SubClass_A = new ArrayList<B>();
List<A> list_A = (ArrayList<A>)list_4__A_AND_SubClass_A;
list_A.add(aObj); // No exception here, Why?

Question_2

在下面的方法中

void method(List<? extends A> list_4__A_AND_SubClass_A){
   //How do i find the passed list is of Type A or B ??
   // To decide List<A> list_A = (ArrayList<A>)list_4__A_AND_SubClass_A;
   //        OR List<B> list_B = (ArrayList<B>)list_4__A_AND_SubClass_A;
}

更新

Q_1

最好我应该避免引用如下的集合进行修改;除非我们非常确定传递的列表是A / B的类型;保持该清单的完整性。

 List<A> list_A = (ArrayList<A>)list_4__A_AND_SubClass_A; 

Q_2

我认为我们可以再从调用方法传递一个参数到调用方法,以便在调用方法时修改列表的完整性。

void method(List<? extends A> list_4__A_AND_SubClass_A, Class<? extends A> obj){
     if (A.class.isAssignableFrom(obj)) {
         List<A> list_A = (List<A>)list_4__A_AND_SubClass_A;
            list_A.add(new A());
            list_A.add(new B());
     } else if (B.class.isAssignableFrom(obj)){
         List<B> list_B = (List<B>)list_4__A_AND_SubClass_A;
            //list_B.add(new A()); //only we can add B
            list_B.add(new B());
     }
}

3 个答案:

答案 0 :(得分:2)

理想情况下,从List<B>List<A>的强制转换应该在运行时抛出异常;遗憾的是Java无法在运行时决定。幸运的是,在编译时,您会收到该演员的警告。

答案 1 :(得分:1)

这一行:

List<A> list_A = (ArrayList<A>)list_4__A_AND_SubClass_A;

生成“未选中”警告,因为您可能(实际上)将仅包含Bs的列表投射到可包含BsAs的列表中(请记住,因为B是A的子类,它是IS A),所以下一行

list_A.add(aObj);

完全没问题,因为你没有注意警告。

通常,对于泛型,List< ? extends A>并不总是与List<A>相同。

回答问题2.
遗憾的是,在编译时检查所有泛型,并且在运行时没有太多信息可用,因此在运行时,您只有一个对象列表,并且无法有效地测试哪种列表。这个“特性”是在Java 1.5中引入后向兼容性和泛型之间的折衷。

答案 2 :(得分:0)

  1. 您在这里List<? extends A>定义通配符类型,这意味着该列表接受A或派生自A的任何内容。因此它不会抛出异常

  2. 您无法在此检测到列表的具体内部类型您必须直接传递,即您的方法签名必须如下

    void方法(列表清单)