2

我正在为作者Jeanne Boyarsky 和 ​​Scott Selikoff 的 OCP 阅读书籍,书中说:第 122 页

? super String

使用下限,我们告诉 Java 该列表将是String 对象的列表或某些对象的列表,这些对象是String 的超类

    List<? super String> superString = new ArrayList<>();
    superString.add(new String());// Valid 
    superString.add(new Object()); // Not Valid ? Why?. Object is a super class of String 

其他示例:

List<? super IOException> exceptions = new ArrayList<Exception>();
exceptions.add(new Exception()); // Invalid, why ? Exception is a superclass of IOException
exceptions.add(new IOException());
exceptions.add(new FileNotFoundException());

我认为这个说法

使用下限,我们告诉 Java 该列表将是String 对象的列表或某些对象的列表,这些对象是String 的超类

应该

使用下限,我们告诉 Java 该列表将是String 对象的列表或超类为 String的某些对象的列表

如果这种情况是真的,那么我们为什么要使用

List<? super IOException> exceptions = new ArrayList<Exception>();

代替

List<? super IOException> exceptions = new ArrayList<IOException>();
4

2 回答 2

2

您需要了解,这些界限(下限和上限)的存在是为了限制/指定变量的类型,而不是为了限制/指定此类集合中元素的类型。

一个例子:

List<? super String> variable = new ArrayList<CharSequence>();

使用此语句,您首先创建一个ArrayList其元素可以是类型CharSequence或它的子类型(例如StringStringBuilder)。

通过该声明,您应该清楚您不能Object在此列表中添加一个。它根本没有实现CharSequence接口。编译器会处理这个问题。

存在用于制作泛型类型的子类型的下限和上限。在这个关于 PECS的问题中解释了它们的使用。

实际上,aList<? super String>是一个包含具体元素类型的列表,但目前还不知道这个具体类型。请参阅我的示例初始化。具体类型是CharSequence. 它只是意味着所有元素都属于该具体类型(或子类型),但这在变量自身的类型中是未知的。

于 2016-06-22T08:14:14.733 回答
1

这是一个很好的解释的链接<? 超级 T> 和 <? 在 Java 中扩展 T>

书上是正确的“?super String”意味着列表可能包含Strings或String的超类型(例如Object,CharSequence)

在你的例子中:

List<? super String> superString = new ArrayList<>();
    superString.add(new String());// 1 
    superString.add(new Object()); // 2

写操作:

1 - 适用于您可以创建的任何类型的列表,因为 String 是一个对象,一个 CharSequence...

List<? super String> list = new ArrayList<Object>();
list.add("String");

2 - 无效,因为它不涵盖所有情况

List<? super String> list = new ArrayList<String>();
list.add(new Object());

给定声明的类型List<? super String>,您只能添加字符串(和字符串子类型),任何小于字符串(超类型)的内容可能与实际元素类型不对应。

例子:

这是一个例子:

interface MyInterface {

}

class MyInterfaceImpl implements MyInterface {

}

class MyInterfaceImplExtra extends MyInterfaceImpl {

}

你可能有以下几种情况:

List<? super MyInterfaceImpl> myList = new ArrayList<MyInterfaceImpl>();

无法编译,因为 myList 变量可能指向 MyInterfaceImpl 或 MyInterface 或 Object 的列表。添加到列表时,不清楚您实际拥有什么样的列表,因此只允许您使用适用于所有情况的值。

myList.add(new MyInterface(){}); // - compile error "not applicable for the arguments"
myList.add(new MyInterfaceImpl()); // - works fine
myList.add(new MyInterfaceImplExtra()); // - works fine

获取值列表的示例。元素类型是 Object ,不能保证更具体的类型。例如在这里你期望字符串但得到一个List<? super String>实际上包含对象的,所以你得到一个java.lang.ClassCastException

List<String> result = (List<String>) getList();
 System.out.println(result.get(0));

 public static List<? super String> getList(){
    List<Object> list = new ArrayList<Object>();
    list.add(new Object());
    return list;
 }

Java 8 中的用法示例:

您在 Stream 接口中有以下方法声明,它将谓词类型限制为 T 或超类型。

Stream<T> filter(Predicate<? super T> predicate);

这确保了给定一个类 Person 定义 name 和 Employee 扩展 Person 并定义一个额外的字段 id ,你不能做这样的事情:

List<Person> list = new ArrayList<Person>() {{
        add(new Person("John"));
        add(new Person("Max"));
        add(new Person("Megan"));
    }};

list.stream().filter((Employee e) -> e.getId().startsWith("1")); // compile error
于 2016-06-22T08:36:20.580 回答