Hel Hel - 2 months ago 9
Java Question

How to use type parameter correctly

I'm confused about type parameter.In the following code, types inside CollectionData angle bracket can be called type parameter. Types inside ArrayList and Generator are not type parameter and should be the same in CollectionData. How to understand it?

//correct
public class CollectionData<T> extends ArrayList<T> {
CollectionData(Generator<T> generator) {

}
}

interface Generator<E> {
E next();
}


Following is wrong. But I can't helping writing this sometimes.

// wrong
public class CollectionData<T> extends ArrayList<E> {
CollectionData(Generator<W> generator) {

}
}

interface Generator<E> {
E next();
}


Added:
In the example above, can type variables be only defined in angle bracket of CollectionData, rather than ArrayList or Generator ? Then ArrayList and CollectionData use these types. Right?

Answer

These generic types are just type variables.

Writing

public class CollectionData<T> extends ArrayList<E> {

is similar to writing

public int func(int x) {
     return y;
}

If there is no variable y, then this code is wrong. But because you declared x, you can use x where appropriate:

public int func(int x) {
     return x;
}

The same is true for generic types. When you write

public class CollectionData<T> extends ArrayList<T>

you are saying that the T inside ArrayList<T> is the identical T as given by the generic type argument to your class. The same is true for the constructors's parameter type.

So, to help you knowing when to write the "correct" code: if you require that both generic types are the same (e.g. the generic type given to your class, and the generic type of your base class or a function's argument), then you have to use the same type variable. This is the same as you would use the same variable inside a function when you need the exact value that is stored in that variable.


Edit for your addendum:

The generic types can only be declared on the class name:

public class CollectionData<T> extends ArrayList<E>

Declares T, but only uses E. This, of course, requires that E has been declared as a generic type (or class, for the fact) somewhere. (When E is a generic type, this should only be valid when CollectionData<T> is inside an outer class which declares E.)

Of course, generic types can also be declared for every function:

public <T> void foo(T x) { x.baz(); }

This declares T and shadows any definition of T. For example, in this context

public class Foo<T> {
    public <T> void foo(T x) { x.baz(); }
}

The T inside the foo method is not the T declared by the class Foo. This works—again—like shadowing variables:

public class Foo {
    int x;
    public int foo(int x) {
        // returns x from argument, not the field of the class
        return x;
    }
}
Comments