下界通配符 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:我可以使用哪些方法?只有对象方法?:
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:比较器在使用时如何允许使用字符串方法?
如果我必须回答问题 2:我会说可选的是指定 "You have to pass me an implementation of Comparator that has a generic type "String" 或实现 "String" 的东西。我这样说对吗?
期待您的回复。
首先,您不应将通配符类型参数与可变性混淆。在 List
的元素类型中使用通配符 不会 阻止修改,它只会对您可以执行的内容施加一些 实用 限制处理列表。
将列表声明为 List<? extends Number>
意味着引用的列表具有 Number
的实际元素类型或 Number
的子类,例如它可以是 List<Integer>
或 List<Double>
。所以你不能添加任意 Number
实例,因为你不知道它是否与实际元素类型兼容。
但您仍然可以添加 null
,因为已知 null
引用与所有引用类型兼容。此外,您始终可以从列表中删除元素,例如调用 remove
或 clear
没有问题。您还可以调用 Collections.swap(list, index1, index2)
之类的方法,这很有趣,因为根据有关通配符类型的正式规则调用 list.set(index1, list.get(index2))
是不合法的,但是将列表传递给可能使用 [= 的另一个方法81=] 代表列表元素类型的类型变量有效。这显然是正确的,因为它只设置来自同一个列表的元素,这些元素必须兼容。
同样,如果你有一个 Comparator<Number>
,你可以调用 Collections.sort(list, comparator)
,作为一个可以处理任意数字的比较器,将能够处理列表中实际存储的任何数字。
总而言之,集合的元素类型中有 ? extends
不会 阻止修改。
如前所述,您不能将任意新元素插入到实际元素类型可能是绑定的未知子类的列表中,例如 List<? extends Number>
。但是当检索一个元素时,你一定会得到一个 Number
实例,因为每个 Number
子类型的实例也是 Number
的实例。当你声明一个 List<? super Number>
时,它的实际元素类型可能是 Number
或 Number
的超类型,例如Object
或 Serializable
。您可以插入任意 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
的实现中,确实不知道 T
或 Comparator
的实际类型参数是什么。但是知道任何 T
类型的流元素都可以传递给比较器的 compare
方法就足够了,该方法可能需要 T
或 T
的超类型。
我知道存在下界通配符的原因之一是在添加新元素时集合不是不可变的。
例如
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:我可以使用哪些方法?只有对象方法?:
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:比较器在使用时如何允许使用字符串方法?
如果我必须回答问题 2:我会说可选的是指定 "You have to pass me an implementation of Comparator that has a generic type "String" 或实现 "String" 的东西。我这样说对吗?
期待您的回复。
首先,您不应将通配符类型参数与可变性混淆。在 List
的元素类型中使用通配符 不会 阻止修改,它只会对您可以执行的内容施加一些 实用 限制处理列表。
将列表声明为 List<? extends Number>
意味着引用的列表具有 Number
的实际元素类型或 Number
的子类,例如它可以是 List<Integer>
或 List<Double>
。所以你不能添加任意 Number
实例,因为你不知道它是否与实际元素类型兼容。
但您仍然可以添加 null
,因为已知 null
引用与所有引用类型兼容。此外,您始终可以从列表中删除元素,例如调用 remove
或 clear
没有问题。您还可以调用 Collections.swap(list, index1, index2)
之类的方法,这很有趣,因为根据有关通配符类型的正式规则调用 list.set(index1, list.get(index2))
是不合法的,但是将列表传递给可能使用 [= 的另一个方法81=] 代表列表元素类型的类型变量有效。这显然是正确的,因为它只设置来自同一个列表的元素,这些元素必须兼容。
同样,如果你有一个 Comparator<Number>
,你可以调用 Collections.sort(list, comparator)
,作为一个可以处理任意数字的比较器,将能够处理列表中实际存储的任何数字。
总而言之,集合的元素类型中有 ? extends
不会 阻止修改。
如前所述,您不能将任意新元素插入到实际元素类型可能是绑定的未知子类的列表中,例如 List<? extends Number>
。但是当检索一个元素时,你一定会得到一个 Number
实例,因为每个 Number
子类型的实例也是 Number
的实例。当你声明一个 List<? super Number>
时,它的实际元素类型可能是 Number
或 Number
的超类型,例如Object
或 Serializable
。您可以插入任意 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
的实现中,确实不知道 T
或 Comparator
的实际类型参数是什么。但是知道任何 T
类型的流元素都可以传递给比较器的 compare
方法就足够了,该方法可能需要 T
或 T
的超类型。