【问题标题】:Generics Wildcards: Assigning Super class object to a Subclass object list泛型通配符:将超类对象分配给子类对象列表
【发布时间】:2013-03-06 19:11:01
【问题描述】:

问题_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?

问题_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());
     }
}

【问题讨论】:

    标签: java generics


    【解决方案1】:

    理想情况下,从List&lt;B&gt;List&lt;A&gt; 的转换应该在运行时抛出异常;不幸的是,Java 无法在运行时做出决定。幸运的是,在编译时,您会收到该演员表的警告。

    【讨论】:

    【解决方案2】:

    这一行:

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

    产生“未检查”警告,因为您可能(并且确实是)将仅包含 Bs 的列表转换为可包含 BsAs 的列表(请记住,因为 B 是 A 的子类, 是A),所以下一行

    list_A.add(aObj);
    

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

    一般来说,对于泛型,List&lt; ? extends A&gt; 并不总是与List&lt;A&gt; 相同。

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

    【讨论】:

    • +1 谢谢!如果您对我在问题中的更新有任何意见,请告诉我。
    • @Kanagavelu Sugumar。您在“Q_1”中破坏了数据完整性,就像在您的演员表之前一样,列表只能包含 B 类型的元素,并且在演员表之后它可以同时包含 AB 的元素,它可能不是很大交易一开始,当所有内容都包含在 1 个方法中时,但是如果列表是您的方法的参数怎么办,那么您真的不能这样做。至于 Q_2,它可能会起作用,但它肯定看起来不正确。问问自己,你真的需要继承吗?阅读这个 -> stackoverflow.com/questions/49002/…
    【解决方案3】:
    1. 你在这里 List&lt;? extends A&gt; 定义通配符类型,这意味着列表接受 A 或派生自 A 的任何内容。因此它不会抛出异常

    2. 你不能在这里检测到列表的具体内部类型你必须直接传递它,即你的方法签名必须如下

      void 方法(列表列表)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-12
      • 2011-09-09
      • 1970-01-01
      • 1970-01-01
      • 2020-05-22
      • 1970-01-01
      • 2019-06-08
      • 2021-01-05
      相关资源
      最近更新 更多