Java 8下界通配符

Anh*_*ran 4 java generics java-8

我正在准备OCP证书,并且遇到了下界通配符的想法。如果我正确理解的话,当我们想让Java知道“绑定类型”总是可以添加到我们的通用Collection中时,将使用下界通配符。

例如:

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]

}
Run Code Online (Sandbox Code Playgroud)

由于“?super Integer”指示类型必须是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

}
Run Code Online (Sandbox Code Playgroud)

现在我们有了一个Predicate,它将接受1个参数,它是一个String或其超类,但是我们不确定它实际上是否是一个String(如果它只是一个对象呢?)。但是,我们仍然可以访问startsWith()类似方法s实际上是一个字符串。

为什么会这样?请给我解释一下。

Era*_*ran 7

Predicate<? super String> pred可以分配为Predicate<String>Predicate<Object>。您正在为其分配一个Predicate<String>,这是允许的。由于您在lambda表达式中使用方法,因此编译器推断s -> s.startsWith("M")为a 。Predicate<String>String

例如,以下代码还将通过编译:

Predicate<? super String> pred = (Object o) -> o.hashCode() > 0;
Run Code Online (Sandbox Code Playgroud)

您还可以看到以下通过编译:

Predicate<String> preds = s -> s.startsWith("M");
Predicate<Object> predo = (Object o) -> o.hashCode() > 0;
Predicate<? super String> pred = preds;
pred = predo;
Run Code Online (Sandbox Code Playgroud)

Predicate<? super String>可以同时分配a Predicate<String>和a Predicate<Object>

也就是说,请注意,pred.test()它将仅接受String,而不接受Object。原因是该pred变量可以引用a Predicate<Object>Predicate<String>在运行时引用,并且String两者都只能接受a 。