Anarantt
Anarantt

Reputation: 289

Generic Method Calls

I have been experimenting with Generic and soon enough I've run into something I cannot explain.
For example:

import java.util.*;
public class Main {
    public static void main(String[] args) {
        //We cannot create List<?> l = new ArrayList<?>();
        List<?> l = MagicClass.factory();
    }
    static class MagicClass {
        public static <T> List<T> factory() {
            return new ArrayList<T>();
        }
    }
}

I don't understand how <T> can be explicit type parameter while this one

<?>

is undefined.

Upvotes: 1

Views: 94

Answers (3)

newacct
newacct

Reputation: 122439

We cannot create List l = new ArrayList();

If you really wanted to do it, you could do

List<?> l = new ArrayList<Object>();

or

List<?> l = new ArrayList<String>();

or

List<?> l = new ArrayList<Math>();

or

List<?> l = new ArrayList<SomeBogusIrrelevantClass>();

There are all correct. Just pick any type that satisfies the bounds; it doesn't even have to be related to what you're doing.

From this, you can see why what you're trying to do is absurd -- you have a list that could be ArrayList<Math> or could be ArrayList<SomeBogusIrrelevantClass> (you don't know). So what can you do with it? Not much.

You can't add anything (besides null) to it. So you have a list where the elements can only have value null; the only thing that can vary is how many nulls. But in that case, you might as well use an integer.

Upvotes: 0

M A
M A

Reputation: 72854

Instantiating a generic type using the wildcard generates a compilation error since the wildcard means any type, while the instantiated ArrayList should have a concrete type. The wildcard can be used for variables or parameter types, but not when creating an instance of the generic type.

This is mentioned as well in this tutorial page:

In generic code, the question mark (?), called the wildcard, represents an unknown type. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type (though it is better programming practice to be more specific). The wildcard is never used as a type argument for a generic method invocation, a generic class instance creation, or a supertype.

On the other hand, in the factory method, T is a type parameter that will be inferred by the compiler, and since the List<?> denotes any type, it is accepted by the compiler.

Upvotes: 2

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476624

<?> is a wildcard, it means as much as: "any type you like". Now since <?> thus doesn't make any assumption of the type used, T can only be more specialized. Thus Java sees Foo<T> as Foo<?>. On the other hand it is rather unwise to do so, because Java has less means to type-check the code. As a result, Java will normally deny to invocate any method where the type parameter is used as input.

Example: the following code won't compile:

    ArrayList<?> foo = new ArrayList<String>();
    foo.add("bar");

This because, Java doesn't know what the T in foo is. It is possible that foo is a ArrayList<Integer>, thus to be safe, it is not allowed.

It can be used if you want for instance to make a method that can accept all kinds of List<?> instances, regardless of the objects stored in them.

You can never construct an instance with a wildcard

The following code won't compile:

ArrayList<?> foo = new ArrayList<?>();

This because at the time of construction, Java has to know which type you will choose.


But in many cases it is used as bounded wildcards. With as typical example:

public void drawAll(List<? extends Shape> shapes) {
    //...
}

This method is given a list of Shape's. Now if you write this as List<Shape>, it requires you to provide an ArrayList<Shape> or LinkedList<Shape> or another collection. But perhaps you have specialized your collection to contain only Quadrilateral instances (Rectangle, Square, Trapezium). If you would use ArrayList<Quadrilateral> on a function drawAll(List<Shape> shapes), you would get a Type-error: indeed, a List<Quadrilateral> is not a List<Shape>, but using bounderies, you enforce that the generic type extends for instance from another type.

Upvotes: 2

Related Questions