I'm a newbie in Generic and my question is: what difference between two functions:
function 1:
public static <E> void funct1 (List<E> list1) {
}
function 2:
public static void funct2(List<?> list) {
}
The first signature says: list1 is a List of Es.
The second signature says: list is a List of instances of some type, but we don't know the type.
The difference becomes obvious when we try to change the method so it takes a second argument, which should be added to the list inside the method:
import java.util.List;
public class Experiment {
public static <E> void funct1(final List<E> list1, final E something) {
list1.add(something);
}
public static void funct2(final List<?> list, final Object something) {
list.add(something); // does not compile
}
}
The first one works nicely. And you can't change the second argument into anything that will actually compile.
Actually I just found an even nicer demonstration of the difference:
public class Experiment {
public static <E> void funct1(final List<E> list) {
list.add(list.get(0));
}
public static void funct2(final List<?> list) {
list.add(list.get(0)); // !!!!!!!!!!!!!! won't compile !!!!!!!!!
}
}
One might as why do we need <?>
when it only restricts what we can do with it (as @Babu_Reddy_H did in the comments). I see the following benefits of the wildcard version:
The caller has to know less about the object he passes in. For example if I have a Map of Lists: Map<String, List<?>>
I can pass its values to your function without specifying the type of the list elements. So
If I hand out objects parameterized like this I actively limit what people know about these objects and what they can do with it (as long as they stay away from unsafe casting).
These two make sense when I combine them: List<? extends T>
. For example consider a method List<T> merge(List<? extends T>, List<? extends T>)
, which merges the two input lists to a new result list. Sure you could introduce two more type parameters, but why would you want to? It would be over specifying things.
add
method work, while get
doesn't give you anything useful. Of course that triggers the next question: why don't generics have lower bounds?For a more in depth answer see: When to use generic methods and when to use wild-card? and http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ203
Generics makes the collection more type safe.
List<E>
: E here is the Type Parameter, which can be used to determine the content type of the list, but there was No
way to check what was the content during the runtime
.
Generics are checked only during compilation time.
<? extends String>
: This was specially build into java, to handle the problem which was with the Type Parameter. "? extends String"
means this List can have
objects which IS-A String.
For eg:
Animal class
Dog class extends Animal
Tiger class extends Animal
So using "public void go(ArrayList<Animal> a)"
will NOT accept
Dog or Tiger as its content but Animal.
"public void go(ArrayList<? extends Animal> a)"
is whats needed to make the ArrayList take in Dog and Tiger type.
Check for references in Head First Java.
List<E>
as a parameter type says that the parameter must be a list of items with any object type. Moreover, you can bind the E
parameter to declare references to list items inside the function body or as other parameter types.
The List<?>
as a parameter type has the same semantics, except that there is no way to declare references to the items in the list other than to use Object
. Other posts give additional subtle differences.
The first is a function that accepts a parameter that must be a list of items of E type.
the second example type is not defined
List<?> list
so you can pass list of any type of objects.
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