Can all wildcards in Java be replaced with non-character types?

I cannot find an example in which wildcards cannot be replaced with a common one. For example:

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

equivalently

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

or

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

equivalently

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

Therefore, I do not understand why the template was created, since generics are already doing this work. Any ideas or comments?

+7
source share
3 answers

No, it is not always replaced.

 List<? extends Reader> foo(); 

not equivalent

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

because you don’t know T when you call foo() (and you cannot know what List<T> foo() returns. The same thing happens in the second example.

a demonstration of the use of wildcards can be found in this (my) answer .

+7
source

The easy answer is that deeper-level wildcards cannot be replaced with a variable of type

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

very different from

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

This is because the substitution capture transformation applies only to level 1 wildcards. Let's talk about it.

Due to the extensive capture conversion, in most places, the compiler treats wildcards as if they were type variables. Therefore, it is true that a programmer can replace a wildcard with type variables in such places, a kind of manual capture conversion.

Since the type variable created by the compiler to convert the capture is not available to the programmer, this has the limiting effect mentioned by @josefx. For example, the compiler treats a List<?> Object as a List<W> object; since W is internal to the compiler, although it has an add(W item) method, it is not possible for the programmer to call it because it does not have an element of type W However, if a programmer "manually" converts a wildcard into a variable of type T , he can have an element of type T and call add(T item) on it.

Another rather random case when a wildcard cannot be replaced with a variable of the type:

 class Base List<? extends Number> foo() class Derived extends Base List<Integer> foo() 

Here foo () is overridden by the covariant return type, since List<Integer> is a subtype of List<? extends Number List<? extends Number . This will not work if the wildcard is replaced with a type variable.

+2
source

There is a difference in usage in your examples.

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

returns a list that may contain an unknown subtype of T so that you can get objects of type T from it, but you cannot add to it.

Example T = Number

 List<? extends Number> l = new ArrayList<Integer>(Arrays.asList(new Integer(1))); //Valid since the values are guaranteed to be a subtype of Number Number o = l.get(0); //Invalid since we don't know that the valuetype of the list is Integer l.add(new Integer(1)); 

Thus, a wildcard can be used to invalidate some operations; this can be used by the API to restrict the interface.

Example:

 //Use to remove unliked numbers, thanks to the wildcard //it is impossible to add a Number @Override public void removeNumberCallback(List<? extends Number> list){ list.remove(13); } 
0
source

All Articles