Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic vs wildcard unknown types

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.

like image 348
wrongusername Avatar asked Mar 21 '15 03:03

wrongusername


4 Answers

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.

like image 66
Zielu Avatar answered Oct 20 '22 13:10

Zielu


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.

like image 33
kuujo Avatar answered Oct 20 '22 12:10

kuujo


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

like image 2
Nayuki Avatar answered Oct 20 '22 13:10

Nayuki


Differences between generics and wildcard unknown types:

  • Enforcing a relationship on the types of method arguments (Use Generics)
  • Supporting multiple bounds (Use Generics)
  • Supporting both upper and lower bounds (Use Wildcard)

The related question:

When to use generic methods and when to use wild-card?

like image 2
Benjamin Winters Avatar answered Oct 20 '22 12:10

Benjamin Winters