Reputation: 18918
When is it recommended to do:
public <E> boolean hasPropertyX(List<E extends User> alist);
versus
public boolean hasPropertyX(List<? extends User> alist);
It would appear they both work just as well.
Upvotes: 8
Views: 726
Reputation: 37845
Use ? extends
when you only need to retrieve from the List:
User getElement(List<? extends User> list, int i) {
return list.get(i);
}
Use ? super
when you only need to add to the List:
void addElement(List<? super User> list, User u) {
list.add(u);
}
Use E extends
when you both need to retrieve and add:
<E extends User> void swapElements(List<E> list, int i, int j) {
E temp = list.get(i);
list.set(i, list.get(j));
list.set(j, temp);
}
? extends User
: We don't know the exact type of the List, but we can retrieve a User
from it.? super User
: We don't know the exact type of the List, but we can put a User
in it.E extends User
: We don't necessarily know the exact type of the List but it conforms to constraints such that:
E
.E
is at least User
.E
from the List and put E
in the List.See also:
Upvotes: 1
Reputation: 64
Differences between generics and wildcard unknown types:
The related question:
When to use generic methods and when to use wild-card?
Upvotes: 2
Reputation: 18533
Explicitly naming the generic type as E
and not ?
has these uses (as far as I can think of):
0) To tie the return type to some part of the argument type - for example:
public <E> E getSomeElement(List<E> lst) { ... }
// ^ If we don't name the argument type as having E,
// then we can't specify the return type as being E
1) To tie some part of the argument type to some part of the enclosing type:
class Storage<E> {
E item;
public void replace(Storage<E> st) { item = st.item; }
// ^ This wouldn't work if we wrote Storage<?> instead
}
2) To tie some combination of the argument types, return type, and enclosing type (see #0 and #1).
We can get away with the anonymous type name ?
if we don't care about the actual type. Here is a basic example:
boolean allEqual(List<?> lst, Object y) {
for (Object x : lst) { // Any reference can be stored as Object
if (!y.equals(x)) // equals takes an Object
return false;
}
return true;
}
// ^ We could also rewrite this example with List<E> and "E x".
Another example:
int intSum(List<? extends Number> lst) {
int sum = 0;
for (Number x : lst) // We only care that the list element is a Number
sum += x.intValue();
return sum;
}
// ^ We could also rewrite with List<E extends Number> and "E x".
Alternate reading: http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
Upvotes: 2
Reputation: 8185
I suppose in that particular example they both do work effectively the same way in terms of type checking. However, if you extend the generic type to require a base or superclass of some class it can be useful. e.g.
public <E extends User> boolean hasPropertyX(List<E> alist);
This at least enforces that you're receiving some subclass of User
.
EDIT
You can use a wildcard to achieve the same thing:
public boolean hasPropertyX(List<? extends User> alist);
But this won't work if, for example, you want to use the generic for multiple parameters:
public <E extends Automobile> void crashAutos(List<E> list1, List<E> list2);
This enforces the generic type on both arguments, whereas the following code does not force the two lists to contain the same type:
public void crashAutos(List<? extends Automobile> list1, List<? extends Automobile> list2);
I could call that method with two different subclasses of the Automobile
class:
List<Car> cars = ...
List<Truck> trucks = ...
crashAutos(cars, trucks);
Whereas using generics enforces the same type for both arguments.
Upvotes: 2
Reputation: 8552
Without typed return value, the only difference I can think of is explicit typing of the first way of declaration during method call.
So for example you are using it inside typed class C<K extends String>
List<V extends String> input = ...;
boolean var = obj.hasProperty<K>(input);
will raise the compiler error. But why would any one want to do so...
Nice question even if most likely the answer is both are the same.
Upvotes: 4