繁体   English   中英

下限通配符Java - 访问方法

[英]Lower-Bounded Wildcards Java - Access to Methods

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

例如

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:我会说可选是指定“你必须传递一个具有泛型类型”字符串“的比较器的实现或者实现”字符串“的东西。我会说这个是正确的吗?

期待你的回复。

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

将列表声明为List<? extends Number> 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 ? extends在集合的元素类型并不妨碍修改。


如上所述,您不能将任意新元素插入到实际元素类型可能是绑定的未知子类的List<? extends Number> ,例如List<? extends Number> List<? extends Number> 但是您可以保证在检索元素时获得Number实例,因为Number每个子类型实例也是Number的实例。 当你声明一个List<? super Number> List<? super Number> ,它的实际元素类型可能是Number或超类型的Number ,例如ObjectSerializable 您可以插入任意Number实例,因为您知道它将与列表具有的任何实际元素类型兼容,因为它是超类型的数字。 检索实例时,您只知道它是Object的实例,因为它是所有实例的超类型。 要比较? extends ? extends案例,有一个? super ? 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的实现中,确实不知道Comparator T或实际类型参数是什么。 但是,知道任何类型为T流元素都可以传递给比较器的compare方法,这可能需要T或超类型的T ,这就足够了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM