关于泛型:之间的区别<?超级T>和<?在Java中扩展t& gt

Difference between <? super T> and <? extends T> in Java

本问题已经有最佳答案,请猛点这里访问。

ListList有什么区别?

我以前用过List,但它不允许我在其中添加元素list.add(e),而List则允许。


extends

List foo3的通配符声明意味着其中任何一个都是合法的分配:

1
2
3
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
  • 阅读-鉴于上述可能的任务,您保证从List foo3中阅读哪种类型的对象:

    • 您可以阅读Number,因为可以分配给foo3的任何列表都包含NumberNumber的子类。
    • 你不能阅读Integer,因为foo3可能指向List
    • 你不能阅读Double,因为foo3可能指向List
  • 写作-考虑到上述可能的任务,您可以在List foo3中添加哪些类型的对象,这些对象对于上述所有可能的ArrayList任务都是合法的:

    • 不能添加Integer,因为foo3可能指向List
    • 不能添加Double,因为foo3可能指向List
    • 不能添加Number,因为foo3可能指向List
  • 你不能在List中添加任何对象,因为你不能保证它真正指向的是哪种List,所以你不能保证该对象在List中是允许的。唯一的"保证"是你只能从中阅读,你会得到一个TT的子类。

    super

    现在考虑一下List

    List foo3的通配符声明意味着其中任何一项都是合法的转让:

    1
    2
    3
    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
  • 阅读-鉴于上述可能的任务,当您从List foo3阅读时,您保证收到哪种类型的对象:

    • 你不能保证使用Integer,因为foo3可能指向ListList
    • 你不能保证一个Number,因为foo3可能指向一个List
    • 唯一的保证是你会得到一个ObjectObject的子类的实例(但你不知道子类是什么)。
    • 写作-考虑到上述可能的任务,您可以在List foo3中添加哪些类型的对象,这些对象对于上述所有可能的ArrayList任务都是合法的:

      • 您可以添加一个Integer,因为上面的任何列表中都允许使用Integer
      • 您可以添加Integer子类的实例,因为在上述任何列表中都允许使用Integer子类的实例。
      • 不能添加Double,因为foo3可能指向ArrayList
      • 不能添加Number,因为foo3可能指向ArrayList
      • 不能添加Object,因为foo3可能指向ArrayList
    • 胸肌

      记住PECS:"生产者扩展,消费者超级"。

      • "Producer extends"—如果您需要一个List来生成T值(您想从列表中读取Ts),您需要使用? extends T来声明它,例如List。但不能添加到此列表。

      • "消费者超级"—如果你需要一个List来消费T值(你想把T写进列表中),你需要用? super T来声明它,例如List。但是不能保证您可以从这个列表中读取什么类型的对象。

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

      例子

      请注意Java泛型FAQ中的这个示例。注意源列表src(生产列表)如何使用extends,目的列表dest(消费列表)如何使用super

      1
      2
      3
      4
      5
      6
      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));
        }
      }

      也看到如何添加到列表<?扩展数字>数据结构?