Chapter 3. Generics
Prev |  | Next

# Chapter 3. Generics

## Generics in Java 5

This section provides the essential information about generics in Java 5 needed to understand how generics are treated in AspectJ 5. For a full introduction to generics in Java, please see the documentation for the Java 5 SDK.

### Declaring Generic Types

A generic type is declared with one or more type parameters following the type name. By convention formal type parameters are named using a single letter, though this is not required. A simple generic list type (that can contain elements of any type `E`) could be declared:

    		interface List<E> {
    		   Iterator<E> iterator();
    		   void add(E anItem);
    		   E remove(E anItem);
    		}

It is important to understand that unlike template mechanisms there will only be one type, and one class file, corresponding to the `List` interface, regardless of how many different instantiations of the `List` interface a program has (each potentially providing a different value for the type parameter `E`). A consequence of this is that you cannot refer to the type parameters of a type declaration in a static method or initializer, or in the declaration or initializer of a static variable.

A parameterized type is an invocation of a generic type with concrete values supplied for all of its type parameters (for example, `List<String>` or `List<Food>`).

A generic type may be declared with multiple type parameters. In addition to simple type parameter names, type parameter declarations can also constrain the set of types allowed by using the `extends` keyword. Some examples follow:

class Foo<T> {...}

  A class `Foo` with one type parameter, `T`.

class Foo<T,S> {...}

  A class `Foo` with two type parameters, `T` and `S`.

class Foo<T extends Number> {...}

  A class `Foo` with one type parameter `T`, where `T` must be instantiated as the type `Number` or a subtype of `Number`.

class Foo<T, S extends T> {...}

  A class `Foo` with two type parameters, `T` and `S`. `Foo` must be instantiated with a type `S` that is a subtype of the type specified for parameter `T`.

class Foo<T extends Number & Comparable> {...}

  A class `Foo` with one type parameter, `T`. `Foo` must be instantiated with a type that is a subtype of `Number` and that implements `Comparable`.

### Using Generic and Parameterized Types

You declare a variable (or a method/constructor argument) of a parameterized type by specifying a concrete type specfication for each type parameter in the generic type. The following example declares a list of strings and a list of numbers:

            List<String> strings;
            List<Number> numbers;

It is also possible to declare a variable of a generic type without specifying any values for the type parameters (a raw type). For example, `List strings`. In this case, unchecked warnings may be issued by the compiler when the referenced object is passed as a parameter to a method expecting a parameterized type such as a `List<String>`. New code written in the Java 5 language would not be expected to use raw types.

Parameterized types are instantiated by specifying type parameter values in the constructor call expression as in the following examples:

            List<String> strings = new MyListImpl<String>();
            List<Number> numbers = new MyListImpl<Number>();

When declaring parameterized types, the `?` wildcard may be used, which stands for "some type". The `extends` and `super` keywords may be used in conjunction with the wildcard to provide upper and lower bounds on the types that may satisfy the type constraints. For example:

List<?>

  A list containing elements of some type, the type of the elements in the list is unknown.

List<? extends Number>

  A list containing elements of some type that extends Number, the exact type of the elements in the list is unknown.

List<? super Double>

  A list containing elements of some type that is a super-type of Double, the exact type of the elements in the list is unknown.

A generic type may be extended as any other type. Given a generic type `Foo<T>` then a subtype `Goo` may be declared in one of the following ways:

class Goo extends Foo

  Here `Foo` is used as a raw type, and the appropriate warning messages will be issued by the compiler on attempting to invoke methods in `Foo`.

class Goo<E> extends Foo

  `Goo` is a generic type, but the super-type `Foo` is used as a raw type and the appropriate warning messages will be issued by the compiler on attempting to invoke methods defined by `Foo`.

class Goo<E> extends Foo<E>

  This is the most usual form. `Goo` is a generic type with one parameter that extends the generic type `Foo` with that same parameter. So `Goo<String<` is a subclass of `Foo<String>`.

class Goo<E,F> extends Foo<E>

  `Goo` is a generic type with two parameters that extends the generic type `Foo` with the first type parameter of `Goo` being used to parameterize `Foo`. So `Goo<String,Integer<` is a subclass of `Foo<String>`.

class Goo extends Foo<String>

  `Goo` is a type that extends the parameterized type `Foo<String>`.

A generic type may implement one or more generic interfaces, following the type binding rules given above. A type may also implement one or more parameterized interfaces (for example, `class X implements List<String>`, however a type may not at the same time be a subtype of two interface types which are different parameterizations of the same interface.

### Subtypes, Supertypes, and Assignability

The supertype of a generic type `C` is the type given in the extends clause of `C`, or `Object` if no extends clause is present. Given the type declaration

            public interface List<E> extends Collection<E> {... }

then the supertype of `List<E>` is `Collection<E>`.

The supertype of a parameterized type `P` is the type given in the extends clause of `P`, or `Object` if no extends clause is present. Any type parameters in the supertype are substituted in accordance with the parameterization of `P`. An example will make this much clearer: Given the type `List<Double>` and the definition of the `List` given above, the direct supertype is `Collection<Double>`. `List<Double>` is not considered to be a subtype of `List<Number>`.

An instance of a parameterized type `P<T1,T2,...Tn>`may be assigned to a variable of the same type or a supertype without casting. In addition it may be assigned to a variable `R<S1,S2,...Sm>` where `R` is a supertype of `P` (the supertype relationship is reflexive), `m <= n`, and for all type parameters `S1..m`, `Tm` equals `Sm` or `Sm` is a wildcard type specification and `Tm` falls within the bounds of the wildcard. For example, `List<String>` can be assigned to a variable of type `Collection<?>`, and `List<Double>` can be assigned to a variable of type `List<? extends Number>`.

### Generic Methods and Constructors

A static method may be declared with one or more type parameters as in the following declaration:

              static <T> T first(List<T> ts) { ... }

Such a definition can appear in any type, the type parameter `T` does not need to be declared as a type parameter of the enclosing type.

Non-static methods may also be declared with one or more type parameters in a similar fashion:

              <T extends Number> T max(T t1, T t2) { ... }

The same technique can be used to declare a generic constructor.

### Erasure

Generics in Java are implemented using a technique called erasure. All type parameter information is erased from the run-time type system. Asking an object of a parameterized type for its class will return the class object for the raw type (eg. `List` for an object declared to be of type `List<String>`. A consequence of this is that you cannot at runtime ask if an object is an `instanceof` a parameterized type.

Prev |  | Next
Inter-type Declarations | Home | Generics in AspectJ 5