【问题标题】:Java Generics -- Assigning a list of subclass to a list of superclassJava 泛型——将子类列表分配给超类列表
【发布时间】:2011-09-09 18:58:17
【问题描述】:

我有一个关于将子类列表分配给超类列表的基本问题。

所以我有如下内容:

Class B extends A;

List <B> bList = new ArrayList<B>();
List <A> aList = bList; 

为什么最后一次分配失败?抱歉新手问题

【问题讨论】:

标签: java generics


【解决方案1】:

为了解释这一点,让我用整数替换“B”,用数字替换“A”。这只是为了让它更容易解释。

Class Integer extends Number;

List <Integer> iList = new ArrayList<Integer>();
List <Number> nList = iList // will fail

这会失败的原因是因为 nList 可以接受任何数字——它可以接受整数,它可以接受双精度数,或者任何数字的子类。但是,对于 iList 来说,情况并非如此。您不能将 Double 添加到 iList,因为它只接受 Integer 及其子类。希望这有助于向您解释。

【讨论】:

  • 好的。感谢您的解释。我想我现在关注了。
  • 还可以看看 Jon Skeet 在 Daniel Pryden 在问题评论中提到的链接中的精彩回应。
【解决方案2】:

当您声明类型 A 的项目列表时,只能从列表中添加或删除类型 A 的项目。如果您需要包含 A 的子类,请使用通用通配符 ? extends A 来表示。因此,您的代码应该是:

List <? extends A> aList = bList; 

【讨论】:

    【解决方案3】:

    List&lt;B&gt; 不是List&lt;A&gt;

    通过示例:假设您有class B1 extends A{}class B2 extends A{} 那么(如果你能做到的话:

    List<B1> b1 = new AList<B1>();
    List<A> a = b1;
    
    List<B2> b2 = new AList<B2>();
    

    根据假设,您应该能够做到 a.add(新 B2()) 但这是错误的。

    如果您尝试相同的操作但使用arrays 而不是列表,它将编译并在运行时抛出异常。

    我们说数组是协变的,而泛型是不变的

    要编译代码,你有技巧:

    List<? extends A> a = b;
    

    这表示a 是A 的一些子类型 的列表。_但你不知道是哪一个。因此你不能这样做a.put(X)

    【讨论】:

      【解决方案4】:

      List&lt;B&gt;List&lt;A&gt;invariant 类型。你需要的是covariant 类型。在这种情况下,它是List&lt;? extends A&gt;

      【讨论】:

        【解决方案5】:

        因为泛型是严格类型安全的

        你可以拥有

        List<? extends A> aList = bList;
        

        它说aList 可以保存A 的任何类型的列表

        【讨论】:

          【解决方案6】:

          因为List&lt;B&gt; 没有扩展List&lt;A&gt;。例如,Integer 扩展了 NumberLong 也是如此。所以List&lt;Number&gt; 可以同时包含IntegerLong。因此,如果您将List&lt;Integer&gt; 分配给List&lt;Number&gt;,您将能够将Long 添加到您的整数列表中。

          你可以声明

          List<? super B> superB;
          

          这将允许将任何包含 B 及其超类的列表分配给 superB。 但这与您的情况不一样aList=bList

          List<? extends A> extendsA;
          

          例子

              List<? super Integer> superA;
              superA = new ArrayList<Number>();
          
              List<? extends Number> extendsNumber;
              extendsNumber = new ArrayList<Integer>();
          

          【讨论】:

            【解决方案7】:

            乍一看你可能会这样认为

            Class B extends A;
            
            List <B> bList = new ArrayList<B>();
            List <A> aList = bList;
            

            应该可以,当您想象实际使用这些列表时,问题就很明显了:

            A something = new A();
            aList.add( something ); // Should work because aList is a list of A's
            

            但是aList被分配给bList,所以应该和

            bList.add( something ); // Here's the problem
            

            bList.add() 采用B,但somethingA,而A 不是B

            这就是为什么泛型应该(并且是)严格类型安全的原因。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-01-31
              • 1970-01-01
              • 2010-12-02
              • 2013-11-24
              • 1970-01-01
              • 1970-01-01
              • 2022-10-14
              • 1970-01-01
              相关资源
              最近更新 更多