Paul Boddington
Paul Boddington

Reputation: 37645

Arrays of unknown type

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

Answers (2)

newacct
newacct

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

isnot2bad
isnot2bad

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

Related Questions