我正在为OCP证书做准备,我想到了一个更低界通配符的概念。如果我正确理解它,当我们想让Java知道“有界类型”总是可以添加到我们的泛型集合时,就会使用较低的有界通配符。
例如:
public static void addInteger(List<? super Integer> list, Integer i)
{
list.add(i);
}
public static void main(String[] args)
{
List<Number> list = new ArrayList<>();
addInteger(list, 100);
addInteger(list, 200);
System.out.println(list); // [100,200]
}因为"?superclass“表示类型必须是Integer或其超类,因此向列表中添加Integer将在每种情况下都有效。
但是,这段代码仍然像往常一样编译和运行:
public static void main(String[] args)
{
Predicate<? super String> pred = s -> s.startsWith("M"); // still compiles
System.out.println(pred.test("Mon")); // Output true
}现在我们有了一个谓词,它将接受一个参数,它是一个字符串或它的超类,但是我们不确定它是否是字符串(如果它只是一个对象呢?)但是,我们仍然可以访问startsWith()方法,就像s实际上是一个字符串一样。
这一切为什么要发生?请解释给我听。
发布于 2019-06-19 06:32:25
可以为Predicate<? super String> pred分配Predicate<String>或Predicate<Object>。您正在为它分配一个Predicate<String>,这是允许的。编译器推断s -> s.startsWith("M")是一个Predicate<String>,因为在lambda表达式中使用的是String方法。
例如,以下内容也将通过编译:
Predicate<? super String> pred = (Object o) -> o.hashCode() > 0;您还可以看到以下通过编译:
Predicate<String> preds = s -> s.startsWith("M");
Predicate<Object> predo = (Object o) -> o.hashCode() > 0;
Predicate<? super String> pred = preds;
pred = predo;也就是说,可以同时为Predicate<? super String>分配一个Predicate<String>和一个Predicate<Object>。
尽管如此,请注意,pred.test()只接受String,而不接受任何Object。原因是pred变量可以在运行时引用Predicate<Object>或Predicate<String>,而且只有String是可接受的。
发布于 2019-06-19 06:40:01
您似乎对Predicate对象实例(由lambda创建)的类型与对该对象的引用pred类型之间的区别感到困惑。
Predicate实例具有Predicate<String>类型。pred是Predicate<? super String>类型,因此可以为Predicate<Object>和Predicate<String>类型赋值。但是谓词的test方法只能用String对象调用!
这就是? super String绑定所确保的。对象实例总是具有一些具体类型的类型参数,如Object或String。只有引用才能具有通配符类型的类型参数。
https://stackoverflow.com/questions/56661303
复制相似问题