Generics are one meta level removed. You need to walk a mile in the shoes of the compiler to understand them.
The mistake I often see with generics, and the one you seem to make, is that you think Predicate<? extends Person>
means 'this is a predicate that can test any person. An Employee, a Customer - doesn't matter, hence, 'whatever extends Person' right.
But that is not what that means.
After all, imagine it meant that. What is Predicate<Person>
then? A predicate that can test only specifically new Person()
but not new Employer()
? Java doesn't work that way - any instance of Employer can be used as a Person so that would be utterly bizarre.
In fact, Predicate<Person>
means what you want here: A predicate object that can test any person.
So what does Predicate<? extends Person>
mean? This:
A predicate that can test... I don't actually know what it can test. All I know is, whatever it is, it's some type that is either Person or some subtype thereof.
So what point is there to such a thing? Not all that much in this specific case (for predicate). Let's instead think of lists. We have 3 different types that are relevant (remember, Integer and Double both extend Number, and Number extends Object)
List<? extends Number>
List<? super Number>
List<Number>
You can pass a List<Integer>
object to a method that takes a List<? extends Number>
. You cannot pass it to a method that takes a List<Number>
. Why not - Integer extends Number, right? Ah, but inside generics, that's invariant, as in, no, you can't just replace a type with its subtype. After all, I can add a Double
object to a List<Number>
. I can add Number objects to my list, a Double object is a Number object, QED.
But, adding a Double object to a List<Integer>
, that's no good. Hence, a List<? extends Number>
is required - try it, you cannot add things to such a list. For the same reason: List<? extends Number>
does not mean: "A list that can hold numbers - any numbers". Quite the opposite. It means: "A list that can hold.. I do not know what it can hold (hence the question mark!) - all I know is, whatever it holds, it's Number. Or any subclass of Number). Given that, list.get(5)
WILL return an expression of type Number
(given the few things we know, that is safe), but you can't add anything to it (except for the academic case of a literal null
, which is all types).
For Predicate
in particular, Predicate<? extends>
is completely useless, that shouldn't ever show up in any case. Predicate<? super X>
can be quite convenient. After all, that means: "A predicate that can test.. well I do not know what it can test. What I do know, is that it is either X, or some super type of X". Given that information, .test(instanceOfX)
is fine.
Predicate
`
the same thing ?
– AntonBoarf May 12 '23 at 15:58