Reputation: 37645
Why is the expression ?[]
illegal? I don't understand why it is any more suspect than T[]
. I get that there are problems with generic array creation, so I see why things like new T[]
and new ?[3]
are disallowed, but I don't see what's wrong with ?[]
. It would be nice, for example, to be able to have a method signature like void method(?[] arr)
. What's wrong with this?
Also, what is the preferred way to write a method taking an array of unknown type? Should you use
public void method(Object[] arr)
in preference to
public <T> void method(T[] arr)
or is this an exception to the usual rule that you should avoid type parameters in method signatures if the type parameter appears only once?
Upvotes: 2
Views: 7418
Reputation: 122429
Yes, you should use
public void method(Object[] arr)
in preference to
public <T> void method(T[] arr)
because they both accept the same set of potential arguments, and the first one is simpler and has less type parameters.
Why is the expression
?[]
illegal?
Syntactically, because the left side of []
must be an actual type. Linguistically, it's because it is unnecessary, you can use Object[]
instead.
In general, whenever you want to do something like (? extends X)[]
, in your mind, just transform it to X[]
. And similarly, whenever you want to use something like ? extends X
as a standalone type, think of X
instead.
For generics type arguments, ? extends X
is needed because generic types are not covariant (List<A>
is not a subtype of List<B>
even if A
is a subtype of B
). However, array types are covariant (A[]
is a subtype of B[]
if A
is a subtype of B
), so having (? extends X)[]
is unnecessary.
Upvotes: 3
Reputation: 24444
You are mixing up type parameters and type arguments!
Consider the following example of generic type List
:
interface List<T> {
void add(T element);
int size();
T get(int index);
}
Here, T
is the type parameter. It is a placeholder for the 'real' type, that is 'filled in' when the generic type is instantiated. You can use this placeholder inside the implementation of the generic type, e.g. to declare a variable, or as a type argument for another generic type:
class LinkedList<T> implements List<T> {
private Node<T> head; // here, T is the type argument of E in Node<E>
...
}
class Node<E> {
private E element; // here, E is a placeholder for the 'real' type
...
}
A type parameter is a formal parameter like element
is the formal parameter of the method add
in the example above. It is just a placeholder for the value that is specified at runtime!
Now let's use the generic type:
List<String> list = new LinkedList<String>();
Here, String
is the type argument that replaces the type parameter T
of the generic type.
The wildcard ('?') is also some sort of type argument, saying that the concrete type is not known (and irrelevant). So you can use it when instantiating a generic type:
List<?> list = new LinkedList<String>();
Again, ?
is a type argument, so you cannot use it like a type parameter!
Upvotes: 1