9

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.

18
  • @ajb- My problem is statement 2 is getting compiled, though it should not be.Please check my code Commented Jul 10, 2017 at 4:01
  • Why shouldn't statement 2 be compiled? At least from an intuitive look at polymorphism, an I2 of something extends I1 can be called an I2 of something. (In contrast, an I2 of something extends I1 can only be called an I2 of something extends Object because we know that I1 must be a subclass of Object, which is a conclusion I'm guessing the java compiler isn't willing to jump to.) Commented Jul 10, 2017 at 4:30
  • 1
    No it is not duplicate . Please read the question carefully. Commented Jul 10, 2017 at 6:11
  • 1
    @Zia-- I know the difference very well. If you check my question then you will come to know what i want to ask here Commented Jul 10, 2017 at 6:37
  • 2
    Read the second answer on the duplicate question--it's, honestly, better than the first answer--and explains why this question is indeed a duplicate of that question. Commented Jul 10, 2017 at 14:18

2 Answers 2

7

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)

Sign up to request clarification or add additional context in comments.

2 Comments

The closest I can find in JLS is (Java 7, section 4.5.1): The relationship of wildcards to established type theory is an interesting one, which we briefly allude to here. Wildcards are a restricted form of existential types. Given a generic type declaration G<T extends B>, G<?> is roughly analogous to Some X <: B. G<X>.
@Adrian-- finally someone understands this... thanks a lot for your analysis.. :)
2

Let me explain to you with a simple example:

List<String> list = new ArrayList<>(); List<Object> listObject = new ArrayList<>(); listObject = list; 

Here, Object class is Super class of String class, nevertheless you will receive the below specified compilation error because you have specified your list to accept a specific type of Objects only i.e. 'Object' for listObject and 'String' to list.

Type mismatch: cannot convert from List<String> to List<Object> 

On similar explanation below,

//Comparator<I2<? extends Object>> B = A; // expected compilation fail 

The above line is failing because you are trying to typecast two non-matching types:

Type mismatch: cannot convert from Comparator<Test1.I2<? extends Test1.I1>> to Comparator<Test1.I2<? extends Object>> 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.