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
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;
i.e. 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>
, 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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With