简体   繁体   中英

Java 8 lower bounded wildcard

I'm preparing for OCP certificate, and I came across with the idea of a lower bounded wildcard. If I understand it correctly, the lower bounded wildcard is used when we want to let Java know the "bounded type" can always be added to our generic Collection.

For example:

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]

}

Since "? super Integer" indicates that the type must be an Integer or its superclass, adding an Integer to the list will work in each case.

However, this code still compiles and runs like normal:

public static void main(String[] args)
{   
    Predicate<? super String> pred = s -> s.startsWith("M"); // still compiles
    System.out.println(pred.test("Mon")); // Output true

}

Now we have a Predicate that will take 1 parameter which is a String or its super class, but we're not sure it's actually a String or not (What if it's just an Object?). However, we can still access startsWith() method like s is actually a String.

Why does this happen? Please explain to me.

Predicate<? super String> pred Predicate<? super String> pred can be assigned either a Predicate<String> or a Predicate<Object> . You are assigning to it a Predicate<String> , which is allowed. The compiler infers that s -> s.startsWith("M") is a Predicate<String> since you are using a String method in the lambda expression.

For example, the following will also pass compilation:

Predicate<? super String> pred = (Object o) -> o.hashCode() > 0;

You can also see that the following passes compilation:

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

ie Predicate<? super String> Predicate<? super String> can be assigned both a Predicate<String> and a Predicate<Object> .

That said, note that pred.test() will only accept String s, and not any Object . The reason is that the pred variable can reference either a Predicate<Object> or Predicate<String> at runtime, and only a String is acceptable by both.

Your seem to be confused about the difference between the type of the Predicate object instance (that is created by the lambda) and type of pred , the reference to that object.

  • The Predicate instance that is created by the lambda has type Predicate<String> .

  • The reference pred to the object is of type Predicate<? super String> Predicate<? super String> , and can thus be assigned values of both type Predicate<Object> and Predicate<String> . But the test method of the predicate can only be called with String objects!

    That's what the ? super String ? super String bound ensures.

Object instances always have type parameters of some concrete type, like Object or String . Only references to can have type parameters of wildcard types.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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