Hi,

I am having problem understanding the below:

1) List a = new ArrayList();

2) List <?> b = a;

3) List <? extends Object> c = a; // with warning of course

Why there is an unchecked warning at clause 3) while no unchecked warning at 2) ?
I don't see the difference between <?> (Unbounded wildcard) and <? extends Objects> (Since Object is the highest upper bound in Java)

Can anyone help me on this?
Thanks.

Recommended Answers

All 9 Replies

Because the compiler doesn't care that it is "the highest upper bound in Java". It sees only that is has a "restriction" now and that before, it didn't. Also, you do know that interfaces do not extend Object, right? So, if you try to add something where you are only using an interface defined reference type, then you may not be able to add it to that list (I haven't tried but seeing as how all Generics are handled by the compiler using simple reference types I believe that to be true).

I don't see the difference between <?> (Unbounded wildcard) and <? extends Objects> (Since Object is the highest upper bound in Java)

Interesting; you are indeed correct in quoting that there is absolutely no difference between "?" and "? extends Object" except for the fact that parameterized types with unbounded wildcards (List<?>) are reifiable types whereas a parameterized type with a bound (List<? extends Object>) is not reifiable.

Assigning List to List<?> doesn't generate a warning since both are reified types whereas the second one generates warning because List is a reified type whereas List<? extends Object> isn't (i.e. is affected by erasure)

Interesting; you are indeed correct in quoting that there is absolutely no difference between "?" and "? extends Object" except for the fact that parameterized types with unbounded wildcards (List<?>) are reifiable types whereas a parameterized type with a bound (List<? extends Object>) is not reifiable.

Assigning List to List<?> doesn't generate a warning since both are reified types whereas the second one generates warning because List is a reified type whereas List<? extends Object> isn't (i.e. is affected by erasure)

==========================================================================================

What about from List <?> to List <? extends Object>? This doesn't generate a compiler unchecked conversion warning (from reifiable to non reifiable type).

Because the compiler doesn't care that it is "the highest upper bound in Java". It sees only that is has a "restriction" now and that before, it didn't. Also, you do know that interfaces do not extend Object, right? So, if you try to add something where you are only using an interface defined reference type, then you may not be able to add it to that list (I haven't tried but seeing as how all Generics are handled by the compiler using simple reference types I believe that to be true).

=========================================================================================

Interesting .. i need to absorb what you said. Thanks.

What about from List <?> to List <? extends Object>? This doesn't generate a compiler unchecked conversion warning (from reifiable to non reifiable type).

Yes, because now we are dealing with purely generic declarations/code as apposed to mixing generic/raw code, so the normal generics rules apply.

List<?> is an all encompassing type; as long as the RHS is a List, there would never be a problem with the assignment. Think of it as the same as assigning List<? extends Object> or as a matter of fact any generic List declaration to a raw List.

...or so I think. :)

Yes, because now we are dealing with purely generic declarations/code as apposed to mixing generic/raw code, so the normal generics rules apply.

List<?> is an all encompassing type; as long as the RHS is a List, there would never be a problem with the assignment. Think of it as the same as assigning List<? extends Object> or as a matter of fact any generic List declaration to a raw List.

...or so I think. :)

=========================================================================================

OH MY GOD!!! Finally i see the light!! Holy Crap!
Now i see the whole picture.
Please correct me if i am wrong.

Rule 1)

If going by pure generic code (no intermixing with legacy code).

<?> same as <? extends object>.

Even though <?> is a reifiable type and <? extends object> is not, since both doesn't allow adding into the reference type (of the above) hence type safety is always guaranteed between the two.

Rule 2)

Mixing legacy code and generics.

Raw -> <?> same since both are reifiable type and also since <?> means could be any type or unknown supertype.

Raw -> <? extends Object> unchecked conversion warning since Raw is a reifiable type and <? extends Object> is not. Hence type safety is not guaranteed at run time.

Hope i get it right. If so thanks a million S.O.S

Almost there. :)

Rule 1)
If going by pure generic code (no intermixing with legacy code).
<?> same as <? extends object>.
Even though <?> is a reifiable type and <? extends object> is not, since both doesn't allow adding into the reference type (of the above) hence type safety is always guaranteed between the two.

As far as generic declarations go, <?> is the same as <? extends Object>. The difference is in the the way both are encoded in the class file. Also, there is one corner case which I have come across wherein <?> can't be blindly replaced by <? extends Object>.

Rule 2)
Mixing legacy code and generics.
Raw -> <?> same since both are reifiable type and also since <?> means could be any type or unknown supertype.
Raw -> <? extends Object> unchecked conversion warning since Raw is a reifiable type and <? extends Object> is not. Hence type safety is not guaranteed at run time.

When mixing legacy and generic code, there are two things which come in play:

  • Assigning generic type to raw type: would always work obviously for backwards compatibility
  • Assigning raw type to generic type: would *never* work since the compiler has no idea what the orignal raw type contains due to erasure. *BUT*, the way I see it, there is an exception to this rule; <?> is the only generic constuct which is not subjected to erasure (is reifiable) and hence the the compiler can be damn sure that assignment from any raw type to <?> would *always* work. So, why doesn't this work with <? extends Object> ? I guess the the compiler here simply checks for erasure and if is present disallows any sort of assignment from a raw to generic type. Unfortuntely, I don't have any references to cite/back this up but I'm pretty sure that's how it works, unless you can of course come up with a sample code which proves this theory false. ;)

HTH :)

If that is the case, why from <?> (a reifiable type) to <? extends Object) (a non reifiable type) does not generate an unchecked conversion warning?

Because the two of them are logically equivalent; hence assigning <?> to <? extends Object> and vice versa works. Even though <? extends Object> is non-refiable, it is still a generic declaration and something which is equivalent to <?> .

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.