下限通配符Java - 访问方法

时间:2017-02-05 10:48:03

标签: java generics wildcard java-stream

我理解存在低限通配符的一个原因是,在添加新元素时,集合不是不可变的。

E.g。

List<? extends Number> obj = new ArrayList<>();//Now this list is immutable
obj.add(new Integer(5));//Does not compile
List<? super Number> objTwo = new ArrayList<>();//This list is mutable
objTwo.add(new Integer(5));//Compiles

以下内容无法编译,因为我试图获取数字的长值。

Q1:我可以使用哪些方法?只有Objects方法?:

public void testLowerBounds(List<? super Number> numbers){
        if (!numbers.isEmpty()){
           System.out.println(numbers.get(0).longValue());//Does not compile
        }    

}

我的问题是如何产生的: 我目前正在学习流,本书指定了以下流方法:

Optional<T> min(Comparator<? super T> comparator)

并按如下方式实施:

Stream<String> s = Stream.of("monkey", "ape", "bonobo");    
Optional<String> min = s.min((s1, s2) -> s1.length()—s2.length());

Q2:比较器在使用时如何允许使用字符串方法?

如果我必须回答Q2:我会说可选是指定&#34;你必须向我传递一个具有泛型类型的比较器的实现&#34; String&#34;或者实现&#34; String&#34;的东西。这样说我是否正确?

期待您的回复。

1 个答案:

答案 0 :(得分:2)

首先,您不应将通配符类型参数与可变性混淆。在List的元素类型中使用通配符阻止修改,它只对您可以对列表执行的操作施加一些实际限制。< / p>

具有声明为List<? extends Number>的列表意味着引用的列表具有实际的元素类型Number或子类Number,例如它可以是List<Integer>List<Double>。因此,您无法添加任意Number实例,因为您无法知道它是否与实际元素类型兼容。

但您仍然可以添加null,因为已知null引用与所有引用类型兼容。此外,您始终可以从列表中删除元素,例如毫无问题地致电removeclear。你也可以调用类似Collections.swap(list, index1, index2)的方法,这很有意思,因为有关通配符类型的正式规则调用list.set(index1, list.get(index2))是不合法的,但是将列表传递给另一个可能使用非通配符的方法通配符类型变量表示列表的元素类型有效。这显然是正确的,因为它只设置源自同一列表的元素,这些元素必须兼容。

同样,如果你有Comparator<Number>,你可以调用Collections.sort(list, comparator)作为可以处理任意数字的比较器,能够处理列表中实际存储的任何数字。

总结一下,在集合的元素类型中使用? extends 会阻止修改。

如上所述,您不能将任意新元素插入到实际元素类型可能是绑定的未知子类的列表中,例如List<? extends Number>。但是,在检索元素时,您可以保证获得Number实例,因为Number的每个子类型实例也是Number的实例。声明List<? super Number>时,其实际元素类型可能是Number或超级类型Number,例如ObjectSerializable。您可以插入任意Number实例,因为您知道它将与列表具有的任何实际元素类型兼容,因为它是超类型的数字。检索实例时,您只知道它是Object的实例,因为它是所有实例的超类型。为了与? extends案例进行比较,拥有? super声明不会阻止阅读,它只会带来一些实际限制。同样,您仍然可以将其传递给Collections.swap,因为无论我们对实际类型知之甚少,插入我们刚从同一列表中检索到的内容都有效。

在你的第二个问题中,你会让双方感到困惑。您现在不是在查看min的实现,而是在调用者min(Comparator<? super T> c)的声明允许调用者传递任何使用T或超类型T参数化的比较器。因此,当您有Stream<String>时,将Comparator<String>传递给min方法是有效的,这正是您通过(s1, s2) -> s1.length()—s2.length() lambda表达式实现的方法(尽管如此) ,我更喜欢Comparator.comparingInt(String::length))。

min的实现中,确实不知道TComparator的实际类型参数是什么。但是,知道任何类型为T的流元素都可以传递给比较器的compare方法就足够了,该方法可能需要T或超级类型T

相关问题