我正在准备 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]
}
由于“? super Integer”表示类型必须是 Integer 或其父类(super class),因此在每种情况下都可以将 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
}
现在我们有一个 Predicate 将采用 1 个参数,该参数是一个 String 或其父类(super class),但我们不确定它是否实际上是一个 String(如果它只是一个 Object 怎么办?)。但是,我们仍然可以访问 startsWith()
方法,就像 s
实际上是一个字符串。
为什么会这样?请给我解释一下。
最佳答案
Predicate<? super String> pred
可以分配一个 Predicate<String>
或 Predicate<Object>
.您正在为其分配 Predicate<String>
,这是允许的。编译器推断 s -> s.startsWith("M")
是 Predicate<String>
因为你使用的是 String
lambda 表达式中的方法。
例如,以下也会通过编译:
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
s,而不是任何 Object
.原因是 pred
变量可以引用 Predicate<Object>
或 Predicate<String>
在运行时,只有一个 String
双方都可以接受。
关于Java 8 下界通配符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56661303/