Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between Bounded Type parameter (T extends) and Upper Bound Wildcard (? extends)

I know that there was a similar question already posted, although I think mine is somewhat different...

Suppose you have two methods:

// Bounded type parameter
private static <T extends Number> void processList(List<T> someList) {

}

// Upper bound wildcard
private static void processList2(List<? extends Number> someList) {
    // ...
}

As far as I know, both methods accepts arguments, that are List of type Number or List of subtype of Number.

But what's the difference between the two methods after all?

like image 802
ThomasMX Avatar asked Aug 14 '16 17:08

ThomasMX


People also ask

What is the difference between upper bounded wildcards and bounded type parameters?

What is the difference between a wildcard bound and a type parameter bound? A wildcard can have only one bound, while a type parameter can have several bounds. A wildcard can have a lower or an upper bound, while there is no such thing as a lower bound for a type parameter.

What is the difference between bounded and unbounded wildcards in Java generics?

both bounded and unbounded wildcards provide a lot of flexibility on API design especially because Generics is not covariant and List<String> can not be used in place of List<Object>. Bounded wildcards allow you to write methods that can operate on Collection of Type as well as Collection of Type subclasses.

What is an upper bounded wildcard?

You can use an upper bounded wildcard to relax the restrictions on a variable. For example, say you want to write a method that works on List<Integer>, List<Double>, and List<Number>; you can achieve this by using an upper bounded wildcard.

What is a bounded type parameter?

There may be times when you want to restrict the types that can be used as type arguments in a parameterized type. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.


2 Answers

There are several differences between the two syntaxes during compile time :

  • With the first syntax, you can add elements to someList but with the second, you can't. This is commonly known as PECS and less commonly known as the PUT and GET prinicple.
  • With the first syntax, you have a handle to the type parameter T so you can use it to do things such as define local variables within the method of type T, cast a reference to the type T, call methods that are available in the class represented by T, etc. But with the second syntax, you don't have a handle to the type so you can't do any of this.
  • The first method can actually be called from the second method to capture the wildcard. This is the most common way to capture a wildcard via a helper method.

    private static <T extends Number> void processList(List<T> someList) {
        T n = someList.get(0);
        someList.add(1,n); //addition allowed.   
    }
    
    private static void processList2(List<? extends Number> someList) {
        Number n = someList.get(0);
        //someList.add(1,n);//Compilation error. Addition not allowed.
        processList(someList);//Helper method for capturing the wildcard
    }
    

Note that since generics are compile time sugar, these differences at a broader level are only limited to the compilation.

like image 188
Chetan Kinger Avatar answered Oct 18 '22 09:10

Chetan Kinger


I can think of the below differences :

a) Modifying your list inside the method, consider the below code :

    // Bounded type parameter
    private static <T extends Number> void processList(List<T> someList)
    {

       
       T t = someList.get(0);
       if ( t.getClass() == Integer.class )
       {
           Integer myNum = new Integer(4);
           someList.add((T) myNum);
       }
       
    }

    // Upper bound wildcard
    private static void processList2(List<? extends Number> someList)
    {
        Object o = someList.get(0);
        if ( o instanceof Integer )
        {
            Integer myNum = new Integer(4);
            someList.add(myNum); // Compile time error !!
        }
    }

With wildcard, you cannot add elements to the list! The compiler tells you that it doesn't know what is myNum. But in the first method, you could add an Integer by first checking if T is Integer, with no compile time error.

b) The first method is called generic method. It follows the syntax that is defined for a generic method. The upper bounds specified in the method definition are used to restrict the parameter types.

The second one is NOT necessarily called a generic method, it is a normal method that happens to accept a generic parameter. The wildcard ? with extends keyword is used as a means of relaxing the types that the method can accept.

like image 26
SomeDude Avatar answered Oct 18 '22 11:10

SomeDude