【问题标题】:Difference between <? super T> and <? extends T> in Java [duplicate]<? 之间的区别超级 T> 和 <?在Java中扩展T> [重复]
【发布时间】:2011-05-19 14:18:58
【问题描述】:

List&lt;? super T&gt;List&lt;? extends T&gt; 有什么区别?

我曾经使用List&lt;? extends T&gt;,但它不允许我向其中添加元素list.add(e),而List&lt;? super T&gt; 可以。

【问题讨论】:

标签: java generics collections


【解决方案1】:

super 是下限,extends 是上限。

根据http://download.oracle.com/javase/tutorial/extra/generics/morefun.html

解决方案是使用以下形式 我们还没有看到的有界通配符: 具有下限的通配符。这 句法 ? super T 表示未知数 类型是 T(或 T 本身;记住超类型 关系是自反的)。这是双 我们曾经做过的有界通配符 使用,我们在哪里使用?将 T 扩展到 表示一个未知类型,它是 T的亚型。

【讨论】:

    【解决方案2】:

    extends

    List&lt;? extends Number&gt; foo3 的通配符声明意味着这些都是合法的赋值:

    List<? extends Number> foo3 = new ArrayList<Number>();  // Number "extends" Number (in this context)
    List<? extends Number> foo3 = new ArrayList<Integer>(); // Integer extends Number
    List<? extends Number> foo3 = new ArrayList<Double>();  // Double extends Number
    
    1. 读取 - 鉴于上述可能的分配,您保证从List foo3 读取什么类型的对象:

      • 您可以读取Number,因为任何可以分配给foo3 的列表都包含NumberNumber 的子类。
      • 您无法读取Integer,因为foo3 可能指向List&lt;Double&gt;
      • 您无法读取Double,因为foo3 可能指向List&lt;Integer&gt;
    2. 写作 - 鉴于上述可能的分配,您可以向List foo3 添加什么类型的对象,这对于所有 上述可能的ArrayList 分配是合法的:

      • 您无法添加Integer,因为foo3 可能指向List&lt;Double&gt;
      • 您不能添加Double,因为foo3 可能指向List&lt;Integer&gt;
      • 您不能添加Number,因为foo3 可能指向List&lt;Integer&gt;

    您不能向List&lt;? extends T&gt; 添加任何对象,因为您无法保证它真正指向的是哪种List,因此您无法保证该对象在该@987654351 中是允许的@。唯一的“保证”是您只能从中读取,您将获得TT 的子类。

    super

    现在考虑List &lt;? super T&gt;

    List&lt;? super Integer&gt; foo3 的通配符声明意味着这些都是合法的赋值:

    List<? super Integer> foo3 = new ArrayList<Integer>();  // Integer is a "superclass" of Integer (in this context)
    List<? super Integer> foo3 = new ArrayList<Number>();   // Number is a superclass of Integer
    List<? super Integer> foo3 = new ArrayList<Object>();   // Object is a superclass of Integer
    
    1. 阅读 - 鉴于上述可能的分配,当您从List foo3 阅读时,您保证会收到什么类型的对象:

      • 不能保证您是Integer,因为foo3 可能指向List&lt;Number&gt;List&lt;Object&gt;
      • 不能保证您是 Number,因为 foo3 可能指向 List&lt;Object&gt;
      • 唯一保证是您将获得 Object 的实例或Object 的子类(但您不知道是什么子类)。
    2. 写作 - 鉴于上述可能的分配,您可以向List foo3 添加什么类型的对象,这对于所有 上述可能的ArrayList 分配是合法的:

      • 您可以添加Integer,因为上述任何列表中都允许使用Integer
      • 您可以添加Integer 子类的实例,因为上述任何列表都允许Integer 子类的实例。
      • 您不能添加Double,因为foo3 可能指向ArrayList&lt;Integer&gt;
      • 您不能添加Number,因为foo3 可能指向ArrayList&lt;Integer&gt;
      • 您无法添加Object,因为foo3 可能指向ArrayList&lt;Integer&gt;

    PECS

    记住PECS“生产者扩展,消费者超级”

    • “Producer Extends” - 如果你需要一个List 来产生T 值(你想从列表中读取Ts),你需要声明它与? extends T,例如List&lt;? extends Integer&gt;。但您不能添加到此列表中。

    • "Consumer Super" - 如果你需要一个List 来消费T 值(你想将Ts 写入列表中),你需要声明它与? super T,例如List&lt;? super Integer&gt;。但是不能保证您可以从这个列表中读取什么类型的对象。

    • 如果您需要同时读取和写入列表,则需要完全声明它,不要使用通配符,例如List&lt;Integer&gt;

    示例

    注意this example from the Java Generics FAQ。注意源列表src(生产列表)如何使用extends,目标列表dest(消费列表)如何使用super

    public class Collections { 
      public static <T> void copy(List<? super T> dest, List<? extends T> src) {
          for (int i = 0; i < src.size(); i++) 
            dest.set(i, src.get(i)); 
      } 
    }
    

    另见 How can I add to List<? extends Number> data structures?

    【讨论】:

    • @BertF,好清晰的解释,至少比 doc.oracle 的解释好 3405691582 倍
    • 我已经多次达到这个答案。我希望我可以投票不止一次。你知道你在google search results 中排名第一吗?
    • @Bert F ' super VEGETABLE>' NOT 描述了可以添加到 'foo' 的内容 - 它描述了 'foo' 可以指向的列表类型。 '列表 super VEGETABLE> foo' 表示 'foo' 在任何给定时间都指向 List 或 LIST,但你不知道是哪个。因此,您只能提供双方都想要的 'foo' 东西。两个列表都可以被赋予 VEGETABLE 或 VEGETABLE 的子类,但不能提供 FOOD 或 MEAT(因为 List 不能吃 FOOD 或 MEAT - 已经是 VEGETABLE)。
    • 在学习泛型之前,我曾经喜欢过java。
    • @Danon 更像那个帖子是这个答案的副本。这个答案是 2010 年的,那个博客是 2016 年的。
    【解决方案3】:

    使用 extends 您只能从集合中获取。你不能投入其中。另外,虽然 super 允许 get 和 put,但 get 期间的返回类型是 ?超级T

    【讨论】:

      【解决方案4】:

      通用通配符针对两个主要需求:

      从泛型集合中读取 插入通用集合 使用通用通配符定义集合(变量)的方法有三种。它们是:

      List<?>           listUknown = new ArrayList<A>();
      List<? extends A> listUknown = new ArrayList<A>();
      List<? super   A> listUknown = new ArrayList<A>();
      

      List&lt;?&gt; 表示输入到未知类型的列表。这可能是List&lt;A&gt;List&lt;B&gt;List&lt;String&gt; 等。

      List&lt;? extends A&gt; 表示作为class Asubclasses of A 实例的对象列表(例如B 和C)。 List&lt;? super A&gt; 表示将列表键入A classsuperclass of A

      阅读更多:http://tutorials.jenkov.com/java-generics/wildcards.html

      【讨论】:

        【解决方案5】:

        想象一下有这种层次结构

        1。扩展

        通过写作

            List<? extends C2> list;
        

        您是说list 将能够引用类型为ArrayList 的对象,其泛型类型是C2 (C2) 的7 个子类型 之一包括):

        1. C2:new ArrayList&lt;C2&gt;();,(可以存储C2或子类型的对象)或
        2. D1:new ArrayList&lt;D1&gt;();,(可以存储 D1 或子类型的对象)或
        3. D2:new ArrayList&lt;D2&gt;();,(可以存储 D2 或子类型的对象)或者...

        等等。七种不同的情况:

            1) new ArrayList<C2>(): can store C2 D1 D2 E1 E2 E3 E4
            2) new ArrayList<D1>(): can store    D1    E1 E2  
            3) new ArrayList<D2>(): can store       D2       E3 E4
            4) new ArrayList<E1>(): can store          E1             
            5) new ArrayList<E2>(): can store             E2             
            6) new ArrayList<E3>(): can store                E3             
            7) new ArrayList<E4>(): can store                   E4             
        

        对于每种可能的情况,我们都有一组“可存储”类型:此处以图形方式表示 7 个(红色)组

        如您所见,没有一种安全类型对每种情况都通用:

        • 你不能list.add(new C2(){});,因为它可能是list = new ArrayList&lt;D1&gt;();
        • 你不能list.add(new D1(){});,因为它可能是list = new ArrayList&lt;D2&gt;();

        等等。

        2。超级

        通过写作

            List<? super C2> list;
        

        您是说list 将能够引用类型为ArrayList 的对象,其泛型类型是C2 (C2) 的7 个超类型 之一包括):

        • A1:new ArrayList&lt;A1&gt;();,(可以存储 A1 或子类型的对象)或
        • A2:new ArrayList&lt;A2&gt;();,(可以存储 A2 或子类型的对象)或
        • A3:new ArrayList&lt;A3&gt;();,(可以存储 A3 或子类型的对象)或者...

        等等。七种不同的情况:

            1) new ArrayList<A1>(): can store A1          B1 B2       C1 C2    D1 D2 E1 E2 E3 E4
            2) new ArrayList<A2>(): can store    A2          B2       C1 C2    D1 D2 E1 E2 E3 E4
            3) new ArrayList<A3>(): can store       A3          B3       C2 C3 D1 D2 E1 E2 E3 E4
            4) new ArrayList<A4>(): can store          A4       B3 B4    C2 C3 D1 D2 E1 E2 E3 E4
            5) new ArrayList<B2>(): can store                B2       C1 C2    D1 D2 E1 E2 E3 E4
            6) new ArrayList<B3>(): can store                   B3       C2 C3 D1 D2 E1 E2 E3 E4
            7) new ArrayList<C2>(): can store                            C2    D1 D2 E1 E2 E3 E4
        

        对于每种可能的情况,我们都有一组“可存储”类型:此处以图形方式表示 7 个(红色)组

        如您所见,这里我们有七种安全类型,它们在每种情况下都是通用的:C2D1D2E1E2、@987654355 @, E4.

        • 您可以list.add(new C2(){});,因为无论我们引用哪种列表,C2 都是允许的
        • 您可以list.add(new D1(){});,因为无论我们引用哪种列表,D1 都是允许的

        等等。您可能注意到这些类型对应于从类型C2 开始的层次结构。

        注意事项

        如果你想进行一些测试,这里是完整的层次结构

        interface A1{}
        interface A2{}
        interface A3{}
        interface A4{}
        
        interface B1 extends A1{}
        interface B2 extends A1,A2{}
        interface B3 extends A3,A4{}
        interface B4 extends A4{}
        
        interface C1 extends B2{}
        interface C2 extends B2,B3{}
        interface C3 extends B3{}
        
        interface D1 extends C1,C2{}
        interface D2 extends C2{}
        
        interface E1 extends D1{}
        interface E2 extends D1{}
        interface E3 extends D2{}
        interface E4 extends D2{}
        

        【讨论】:

        • 看起来 B1、B4、C1 和 C3 不应该在第二张图片上着色。因为这些不包括在图片上方的列表中。
        • @Mike 我不确定你的意思,第二张图片中的那些节点是蓝色的,不是任何集合/案例的一部分
        • @Mike B1 是案例 1 的一部分,B4 是案例 4 的一部分,C1 是案例 1-2-5 的一部分,C3 是案例 3-4-6 的一部分。有没有可能你误解了什么?
        • 在PECS解释的世界里,它是最直接的
        【解决方案6】:

        我喜欢@Bert F 的回答,但这是我的大脑看到的方式。

        我手上有一个 X。如果我想将我的 X写入 到一个列表中,该列表需要是 X 的列表或我的 X 可以在我写入时向上转换到的事物列表,即任何 X 的超类...

        List<? super   X>
        

        如果我得到一个列表并且我想从该列表中读取一个 X,那最好是一个 X 的列表或在我读出它们时可以向上转换到 X 的事物的列表,即任何扩展 X

        List<? extends X>
        

        希望这会有所帮助。

        【讨论】:

          【解决方案7】:

          基于Bert F's answer我想解释一下我的理解。

          假设我们有 3 个类

          public class Fruit{}
          
          public class Melon extends Fruit{}
          
          public class WaterMelon extends Melon{}
          

          我们来了

          List<? extends Fruit> fruitExtendedList = …
          
          //Says that I can be a list of any object as long as this object extends Fruit.
          

          好的,现在让我们尝试从fruitExtendedList 中获取一些值

          Fruit fruit = fruitExtendedList.get(position)
          
          //This is valid as it can only return Fruit or its subclass.
          

          再试一次

          Melon melon = fruitExtendedList.get(position)
          
          //This is not valid because fruitExtendedList can be a list of Fruit only, it may not be 
          //list of Melon or WaterMelon and in java we cannot assign sub class object to 
          //super class object reference without explicitly casting it.
          

          WaterMelon waterMelon = fruitExtendedList.get(position)
          

          现在让我们尝试在fruitExtendedList中设置一些对象

          添加水果对象

          fruitExtendedList.add(new Fruit())
          
          //This in not valid because as we know fruitExtendedList can be a list of any 
          //object as long as this object extends Fruit. So what if it was the list of  
          //WaterMelon or Melon you cannot add Fruit to the list of WaterMelon or Melon.
          

          添加 Melon 对象

          fruitExtendedList.add(new Melon())
          
          //This would be valid if fruitExtendedList was the list of Fruit but it may 
          //not be, as it can also be the list of WaterMelon object. So, we see an invalid 
          //condition already.
          

          最后让我们尝试添加 WaterMelon 对象

          fruitExtendedList.add(new WaterMelon())
          
          //Ok, we got it now we can finally write to fruitExtendedList as WaterMelon 
          //can be added to the list of Fruit or Melon as any superclass reference can point 
          //to its subclass object.
          

          但是等等如果有人决定制作一种新型的柠檬怎么办?让我们说一下SaltyLemon as

          public class SaltyLemon extends Lemon{}
          

          现在fruitExtendedList 可以是Fruit、Melon、WaterMelon 或SaltyLemon 的列表。

          所以,我们的声明

          fruitExtendedList.add(new WaterMelon())
          

          也无效。

          基本上我们可以说我们不能向fruitExtendedList 写入任何内容。

          总结一下List&lt;? extends Fruit&gt;

          现在让我们看看

          List<? super Melon> melonSuperList= …
          
          //Says that I can be a list of anything as long as its object has super class of Melon.
          

          现在让我们尝试从 melonSuperList 中获取一些价值

          Fruit fruit = melonSuperList.get(position)
          
          //This is not valid as melonSuperList can be a list of Object as in java all 
          //the object extends from Object class. So, Object can be super class of Melon and 
          //melonSuperList can be a list of Object type
          

          同样,Melon、WaterMelon 或任何其他对象都无法读取。

          但请注意,我们可以读取 Object 类型的实例

          Object myObject = melonSuperList.get(position)
          
          //This is valid because Object cannot have any super class and above statement 
          //can return only Fruit, Melon, WaterMelon or Object they all can be referenced by
          //Object type reference.
          

          现在,让我们尝试从 melonSuperList 中设置一些值。

          添加Object类型的对象

          melonSuperList.add(new Object())
          
          //This is not valid as melonSuperList can be a list of Fruit or Melon.
          //Note that Melon itself can be considered as super class of Melon.
          

          添加水果类型对象

          melonSuperList.add(new Fruit())
          
          //This is also not valid as melonSuperList can be list of Melon
          

          添加 Melon 类型对象

          melonSuperList.add(new Melon())
          
          //This is valid because melonSuperList can be list of Object, Fruit or Melon and in 
          //this entire list we can add Melon type object.
          

          添加 WaterMelon 类型对象

          melonSuperList.add(new WaterMelon())
          
          //This is also valid because of same reason as adding Melon
          

          综上所述,我们可以在melonSuperList中加入Melon或者它的子类,只读Object类型的对象。

          【讨论】:

            【解决方案8】:

            这里最令人困惑的是,无论我们指定什么类型限制,赋值都只能以一种方式工作:

            baseClassInstance = derivedClassInstance;
            

            你可能认为Integer extends NumberInteger 可以作为&lt;? extends Number&gt;,但编译器会告诉你&lt;? extends Number&gt; cannot be converted to Integer(也就是说,用人类的话说,任何事情都是错误的扩展数字可以转换为整数):

            class Holder<T> {
                T v;
                T get() { return v; }
                void set(T n) { v=n; }
            }
            class A {
                public static void main(String[]args) {
                    Holder<? extends Number> he = new Holder();
                    Holder<? super Number> hs = new Holder();
            
                    Integer i;
                    Number n;
                    Object o;
            
                    // Producer Super: always gives an error except
                    //       when consumer expects just Object
                    i = hs.get(); // <? super Number> cannot be converted to Integer
                    n = hs.get(); // <? super Number> cannot be converted to Number
                                  // <? super Number> cannot be converted to ... (but
                                  //       there is no class between Number and Object)
                    o = hs.get();
            
                    // Consumer Super
                    hs.set(i);
                    hs.set(n);
                    hs.set(o); // Object cannot be converted to <? super Number>
            
                    // Producer Extends
                    i = he.get(); // <? extends Number> cannot be converted to Integer
                    n = he.get();
                    o = he.get();
            
                    // Consumer Extends: always gives an error
                    he.set(i); // Integer cannot be converted to <? extends Number>
                    he.set(n); // Number cannot be converted to <? extends Number>
                    he.set(o); // Object cannot be converted to <? extends Number>
                }
            }
            

            hs.set(i); 可以,因为 Integer 可以转换为 Number 的任何超类(而不是因为 IntegerNumber 的超类,这是不正确的)。

            EDIT 添加了一条关于 Consumer Extends 和 Producer Super 的评论——它们没有意义,因为它们相应地指定了 nothing 而只是 Object。建议您记住 PECS,因为 CEPS 从来没有用处。

            【讨论】:

              【解决方案9】:

              什么时候使用extends和super

              通配符在方法参数中最有用。它们为方法接口提供了必要的灵活性。

              人们经常对何时使用扩展和何时使用超级边界感到困惑。经验法则是get-put原则。如果您从参数化容器中获取某些内容,请使用 extends。

              int totalFuel(List<? extends Vehicle> list) {
              int total = 0;
              for(Vehicle v : list) {
                  total += v.getFuel();
              }
              return total;}
              

              totalFuel 方法从列表中获取 Vehicles,询问他们有多少燃料,然后计算总数。 如果将对象放入参数化容器中,请使用 super。

              int totalValue(Valuer<? super Vehicle> valuer) {
              int total = 0;
              for(Vehicle v : vehicles) {
                  total += valuer.evaluate(v);
              }
              return total;}
              

              totalValue 方法将 Vehicles 放入 Valuer。 知道 extends bound 比 super 更常见是很有用的。

              【讨论】:

                【解决方案10】:

                您可以通过以上所有答案了解为什么.add() 仅限于'&lt;?&gt;''&lt;? extends&gt;',部分仅限于'&lt;? super&gt;'

                但如果你想记住它,这里就是这一切的结论,并且不想每次都去探索答案:

                List&lt;? extends A&gt; 表示这将接受A 的任何ListA 的子类。 但是您不能在此列表中添加任何内容。甚至A 类型的对象也不行。

                List&lt;? super A&gt; 表示这将接受A 的任何列表和A 的超类。 您可以添加 A 类型的对象及其子类。

                【讨论】:

                  【解决方案11】:

                  将项目添加到列表中:

                  • 列表 不允许添加任何东西,除了null 到列表中。

                  • 列表 允许添加任何 X(X 或其子类型)或 null。

                  从列表中获取一个项目:

                  • 当您从 List,您可以将其分配给 X 类型的变量或 X 的任何超类型,包括 Object。
                  • 当您从 List,你只能将它赋值给Object类型的变量。

                  一些例子:

                      List<? extends Number> list1 = new ArrayList<Integer>();
                      list1.add(null);  //OK
                      Number n = list1.get(0);  //OK
                      Serializable s = list1.get(0);  //OK
                      Object o = list1.get(0);  //OK
                  
                      list1.add(2.3);  //ERROR
                      list1.add(5);  //ERROR
                      list1.add(new Object());  //ERROR
                      Integer i = list1.get(0);  //ERROR
                  

                      List<? super Number> list2 = new ArrayList<Number>();
                      list2.add(null);  //OK
                      list2.add(2.3);  //OK
                      list2.add(5);  //OK
                      Object o = list2.get(0);  //OK
                  
                      list2.add(new Object());  //ERROR
                      Number n = list2.get(0);  //ERROR
                      Serializable s = list2.get(0);  //ERROR
                      Integer i = list2.get(0);  //ERROR
                  

                  【讨论】:

                    【解决方案12】:

                    投票的答案涵盖了许多方面的细节。但是,我会尝试以不同的方式回答这个问题。

                    我们需要考虑两件事,

                    1。赋值给列表变量

                    List&lt;? extends X&gt; listvar;

                    在这里,任何X 的列表或X 的子类列表都可以分配到listvar。

                    List<? extends Number> listvar; listvar = new ArrayList<Number>(); listvar = new ArrayList<Integer>();


                    List&lt;? super X&gt; listvar;

                    在这里,任何X 列表或X 超类列表都可以分配到listvar。

                    List<? super Number> listvar; listvar = new ArrayList<Number>(); listvar = new ArrayList<Object>();

                    2。对列表变量执行读或写操作

                    `List<? extends X> listvar;`
                    

                    您可以使用此功能在方法参数中接受一个列表,并对 type X 执行任何操作(注意:您可以仅从列表中读取 X 类型的对象 )。

                    `List<? super Number> listvar;
                    

                    您可以使用此功能接受方法参数中的列表并对类型对象执行任何操作,因为您可以仅从列表中读取对象类型的对象但是是的,这里还有一点,您可以将 X 类型的对象添加到列表中。

                    【讨论】:

                      【解决方案13】:

                      例如, 假设继承顺序为 O > S > T > U > V

                      使用 extends 关键字,

                      正确:

                      List<? extends T> Object = new List<T>();
                      List<? extends T> Object = new List<U>();
                      List<? extends T> Object = new List<V>();
                      

                      不正确:

                      List<? extends T> Object = new List<S>();
                      List<? extends T> Object = new List<O>();
                      

                      超级关键字:

                      正确:

                      List<? super T> Object = new List<T>();
                      List<? super T> Object = new List<S>();
                      List<? super T> Object = new List<O>();
                      

                      不正确:

                      List<? super T> Object = new List<U>();
                      List<? super T> Object = new List<V>();
                      

                      添加对象: 列表对象 = new List();

                      Object.add(new T()); //error
                      

                      但是为什么会出错? 让我们看看List Object初始化的可能性

                      List<? extends T> Object = new List<T>();
                      List<? extends T> Object = new List<U>();
                      List<? extends T> Object = new List<V>();
                      

                      如果我们使用 Object.add(new T());那么只有当

                      List<? extends T> Object = new List<T>(); 
                      

                      但是还有另外两种可能

                      列表对象 = new List(); 列表对象 = 新列表(); 如果我们尝试将 (new T()) 添加到上述两种可能性,则会出错,因为 T 是 U 和 V 的上级。我们尝试将 T 对象 [即 (new T()) ] 添加到 U 和 V 类型的 List 中。高级对象(基类)不能传递给低级对象(子类)。

                      由于额外的两种可能性,即使你使用正确的可能性,Java 也会给你错误,因为 Java 不知道你指的是什么对象。所以你不能将对象添加到 List Object = new List();因为有些可能性是无效的。

                      添加对象: 列表对象 = new List();

                      Object.add(new T()); // compiles fine without error
                      Object.add(new U()); // compiles fine without error
                      Object.add(new V()); // compiles fine without error
                      
                      Object.add(new S()); //  error
                      Object.add(new O()); //  error
                      

                      但是为什么上面两个会出错呢? 我们可以使用 Object.add(new T());仅在以下可能性中,

                      List<? super T> Object = new List<T>();
                      List<? super T> Object = new List<S>();
                      List<? super T> Object = new List<O>();
                      

                      如果我们尝试使用 Object.add(new T()) 在 列表对象 = 新列表(); 和 列表对象 = 新列表(); 那么它会给出错误 这是因为 我们不能将 T object[which is new T()] 添加到 List Object = new List();因为它是 U 类型的对象。我们不能将 T 对象[这是新的 T()] 添加到 U 对象,因为 T 是一个基类,而 U 是一个子类。我们不能将基类添加到子类,这就是发生错误的原因。另一种情况也是如此。

                      【讨论】:

                      【解决方案14】:

                      我想直观地看到差异。假设我们有:

                      class A { }
                      class B extends A { }
                      class C extends B { }
                      

                      List&lt;? extends T&gt; - 阅读和分配:

                      |-------------------------|-------------------|---------------------------------|
                      |         wildcard        |        get        |              assign             |
                      |-------------------------|-------------------|---------------------------------|
                      |    List<? extends C>    |    A    B    C    |                       List<C>   |
                      |-------------------------|-------------------|---------------------------------|
                      |    List<? extends B>    |    A    B         |             List<B>   List<C>   |
                      |-------------------------|-------------------|---------------------------------|
                      |    List<? extends A>    |    A              |   List<A>   List<B>   List<C>   |
                      |-------------------------|-------------------|---------------------------------|
                      

                      List&lt;? super T&gt; - 写作和分配:

                      |-------------------------|-------------------|-------------------------------------------|
                      |         wildcard        |        add        |                   assign                  |
                      |-------------------------|-------------------|-------------------------------------------|
                      |     List<? super C>     |              C    |  List<Object>  List<A>  List<B>  List<C>  |
                      |-------------------------|-------------------|-------------------------------------------|
                      |     List<? super B>     |         B    C    |  List<Object>  List<A>  List<B>           |
                      |-------------------------|-------------------|-------------------------------------------|
                      |     List<? super A>     |    A    B    C    |  List<Object>  List<A>                    |
                      |-------------------------|-------------------|-------------------------------------------|
                      

                      在所有情况下:

                      • 无论通配符如何,您都可以从列表中获取 Object
                      • 无论通配符如何,您都可以随时添加 null 到可变列表中。

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 2014-10-12
                        • 2017-11-29
                        • 2015-11-06
                        • 2012-08-30
                        • 1970-01-01
                        • 2011-10-05
                        • 2015-11-15
                        相关资源
                        最近更新 更多