Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can all wildcards in Java be replaced by non-wildcard types?

I can't find any example where wildcards can't be replaced by a generic. For example:

 public void dummy(List<? extends MyObject> list);

is equivalent to

 public <T> void dummy(List<T extends MyObject> list);

or

 public <T> List<? extends T> dummy2(List<? extends T> list);

is equivalent to

 public <T, U>  List<U extends T> dummy(List<U extends T> list);

So I don't undertand why wildcard was created as generics is already doing the job. Any ideas or comments?

like image 296
Olivier MARTIN Avatar asked Sep 06 '11 08:09

Olivier MARTIN


2 Answers

Nope, it is not always replaceable.

List<? extends Reader> foo();

is not equivalent to

<T> List<T extends Reader> foo();

because you don't know the T when calling foo() (and you cannot know what List<T> will foo() return. The same thing happens in your second example, too.

The demonstration of using wildcards can be found in this (my) answer.

like image 127
jpalecek Avatar answered Oct 12 '22 13:10

jpalecek


An easy answer is that, deeper level wildcards can't be replaced by a type variable

void foo( List<List<?>> arg )

is very different from

<T> 
void foo( List<List<T>> arg)

This is because wildcard capture conversion is only applied to 1st level wildcards. Let's talk about these.

Due to extensive capture conversion, in most places, compiler treats wildcards as if they are type variables. Therefore indeed programmer can replace wildcard with type variables in such places, a sort of manual capture conversion.

Since a type variable created by compiler for capture conversion is not accessible to programmer, this has the restricting effect mentioned by @josefx. For example, compiler treats a List<?> object as a List<W> object; since W is internal to compiler, although it has a method add(W item), there's no way for programmer to invoke it, because he has no item of type W. However, if programmer "manually" converts the wildcard to a type variable T, he can have an item with type T and invoke add(T item) on it.

Another rather random case where wildcard can't be replaced type variable:

class Base
    List<? extends Number> foo()

class Derived extends Base
    List<Integer> foo()

Here, foo() is overriden with a covariant return type, since List<Integer> is a subtype of List<? extends Number. This won't work if the wildcard is replaced with type variable.

like image 34
irreputable Avatar answered Oct 12 '22 13:10

irreputable