Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic notation <?> and < ? extends Object > behaving differently

Tags:

java

generics

To my understanding, <? extends Object> and <?> are same.

However, when I run the following code <? extends Object> does not get compiled and is working as expected but <?> is getting compiled successfully.

public class Test1 
{
    interface I1 
    {
    }

    interface I2<T extends I1> extends Comparable<I2<?>> 
    {
        Comparator<I2<? extends I1>> A = null;
        //Comparator<I2<? extends Object>> B = A; // expected compilation fail
        Comparator<I2<?>> B = A; // compiling successfully.This shouldn't get compile
    }
}

Can some one help me understand this behavior.

like image 422
Sachin Sachdeva Avatar asked Jul 10 '17 03:07

Sachin Sachdeva


People also ask

What is difference between extends and super in generics?

extends Number> represents a list of Number or its sub-types such as Integer and Double. Lower Bounded Wildcards: List<? super Integer> represents a list of Integer or its super-types Number and Object.

How does a generic method differ from a generic type?

From the point of view of reflection, the difference between a generic type and an ordinary type is that a generic type has associated with it a set of type parameters (if it is a generic type definition) or type arguments (if it is a constructed type). A generic method differs from an ordinary method in the same way.

What does extends Object mean?

extends Object> means you can pass an Object or a sub-class that extends Object class.


1 Answers

This question is actually interesting but not asked clearly, which easily makes people think it is a duplicate.

First, an example which I think most people here should understand why it does not work:

class Foo<T> {}
class Bar<T> {}

class Parent{}

public class Test1 
{

    public static void main(String[] args) {
        Foo<Bar<? extends Parent>> a = null;
        Foo<Bar<? extends Object>> b = a;  // does not compile
        Foo<Bar<?>> c = a;                 // does not compile
    }
}

It is obvious: a Foo<Bar<?>> / Foo<Bar<? extends Object>> is not convertible to Foo<Bar<? extends Parent>> (To simply: just like you cannot assign List<Dog> to List<Animal> reference.)


However, in the question you can see the case of Comparator<I2<?>> B = A; does compile, which is contradict with what we see above.

The difference, as specified in my example will be:

class Foo<T> {}
class Bar<T extends Parent> {}

class Parent{}

public class Test1 
{

    public static void main(String[] args) {
        Foo<Bar<? extends Parent>> a = null;
        Foo<Bar<? extends Object>> b = a;  // does not compile
        Foo<Bar<?>> c = a;                 // COMPILE!!
    }
}

By changing class Bar<T> to class Bar<T extends Parent> created the difference. It is a pity that I still cannot find the JLS section that is responsible on this, but I believe it when you declare a generic class with bound in type parameter, the bound is implicitly carried to any wildcard you use against that.

Therefore, the example become:

class Foo<T> {}
class Bar<T extends Parent> {}

class Parent{}

public class Test1 
{

    public static void main(String[] args) {
        Foo<Bar<? extends Parent>> a = null;
        //...
        Foo<Bar<? extends Parent>> c = a;
    }
}

which explain why this compile.

(Sorry I cannot find evidence this is how the language is designed. It will be great if someone can find in JLS for this)

like image 75
Adrian Shum Avatar answered Oct 07 '22 07:10

Adrian Shum