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

Joker :

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.

Adrian Shum :

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)

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=442071&siteId=1