Difference between generic type and wildcard type

JavaGenericsWildcard

Java Problem Overview


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) {
	
}

Java Solutions


Solution 1 - Java

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.

  • finally wildcards can have lower bounds, so with lists you can make the 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: https://stackoverflow.com/questions/18176594/when-to-use-generic-methods-and-when-to-use-wild-card and http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ203

Solution 2 - Java

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.

Solution 3 - Java

List 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.

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.

Solution 4 - Java

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.

Solution 5 - Java

I usually explain the difference between <E> and <?> by a comparison with logical quantifications, that is, universal quantification and existential quantification.

  • corresponds to "forall E, ..."
  • corresponds to "there exists something(denoted by ) such that ...."

Therefore, the following generic method declaration means that, for all class type E, we define funct1

public static <E> void funct1  (List<E>; list1) {

}

The following generic method declaration means that, for some existing class denoted by <?>, we define funct2.

public static void funct2(List<?> list) {

}

Solution 6 - Java

(Since your edit) Those two function signatures have the same effect to outside code -- they both take any List as argument. A wildcard is equivalent to a type parameter that is used only once.

Solution 7 - Java

In addition to those differences mentioned before, there is also an additional difference: You can explicitly set the type arguments for the call of the generic method:

List<Apple> apples = ...
ClassName.<Banana>funct2(apples); // for some reason the compiler seems to be ok
                               // with type parameters, even though the method has none

ClassName.<Banana>funct1(apples); // compiler error: incompatible types: List<Apple>
                                  //                 cannot be converted to List<Banana>

(ClassName is the name of the class containing the methods.)

Solution 8 - Java

In this context, both wild card (?) and type parameter (E) will do the same for you. There are certain edges based on the use cases. Let's say if you want to have a method which may have more than one params like:

public void function1(ArrayList<?> a, ArrayList<?> b){
 // some process
}

public <T> void function2(ArrayList<T> a, ArrayList<T> b){
 // some process
}

in function1 a can be AL of String and b can be AL of the Integer so it is not possible to control the type of both the params but this is easy for the function2. We should use the Type Params (function 2) if we want to use the type later in the method or class

There are some features in WildCard and Type param:

WildCard(?)

  1. It support the upper and lower bound in the type while the Type param (E) supports only upper bound.

Type Param(E)

  1. SomeTime we do not need to pass the actual type ex:

    ArrayList<Integer> ai = new ArrayList<Integer>();
    ArrayList<Double>  ad = new ArrayList<Double>();
    function2(ai, ad);
    //It will compile and the T will be Number.
    

In this case, the compiler infers the type argument for us based on the type of actual arguments

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFioView Question on Stackoverflow
Solution 1 - JavaJens SchauderView Answer on Stackoverflow
Solution 2 - JavaKumar Vivek MitraView Answer on Stackoverflow
Solution 3 - JavaGeneView Answer on Stackoverflow
Solution 4 - JavaPramod KumarView Answer on Stackoverflow
Solution 5 - Javauser3509406View Answer on Stackoverflow
Solution 6 - JavanewacctView Answer on Stackoverflow
Solution 7 - JavafabianView Answer on Stackoverflow
Solution 8 - Javaakhil singhalView Answer on Stackoverflow