Parameterized Types

4.5 Parameterized Types

A generic class or interface declaration C (§8.1.2, §9.1.2) with one or more type parameters A 1 ,..., A n which have corresponding bounds B 1 ,..., B n defines a set of parameterized types, one for each possible invocation of the type parameter section.

Each parameterized type in the set is of the form C <T 1 ,..., T n > where each type argument T i ranges over all types that are subtypes of all types listed in the corresponding bound. That is, for each bound type S i in B i , T i is a subtype of S i [F 1 :=T 1 ,...,F n :=T n ] .

A parameterized type is written as a ClassType or InterfaceType that contains at least one type declaration specifier immediately followed by a type argument list <T 1 ,..., T n > . The type argument list denotes a particular invocation of the type parameters of the generic type indicated by the type declaration specifier.

Given a type declaration specifier immediately followed by a type argument list, let C be the final Identifier in the specifier.

It is a compile-time error if C is not the name of a generic class or interface, or if the number of type arguments in the type argument list differs from the number

of type parameters of C .

be a parameterized type. It must be the case that, after P is subjected to capture conversion (§5.1.10) resulting in the type C <X 1 ,..., X n > , for each type argument X i (1 ≤ i ≤ n), X i <: B i [A 1 :=X 1 ,...,A n :=X n ] (§4.10), or a compile- time error occurs.

Let P = C <T 1 ,..., T n >

The notation [A i :=T i ] denotes substitution of the type variable A i with the type T i for 1 ≤ i ≤ n, and is used throughout this specification.

In this specification, whenever we speak of a class or interface type, we include the generic version as well, unless explicitly excluded.

Examples of parameterized types: • Vector<String>

• Seq<Seq<A>> • Seq<String>.Zipper<Integer>

TYPES, VALUES, AND VARIABLES Type Arguments and Wildcards 4.5.1

• Collection<Integer> • Pair<String,String>

Examples of incorrect invocations of a generic type: • Vector<int> is illegal, as primitive types cannot be type arguments.

• Pair<String> is illegal, as there are not enough type arguments. • Pair<String,String,String> is illegal, as there are too many type arguments.

A parameterized type may be an invocation of a generic class or interface which is nested. For example, if a non-generic class C has a generic member class D <T> , then C .D<Object> is a parameterized type. And if a generic class C <T> has a non-generic member class D , then the member type C <String>.D is a parameterized type, even though the class D is not generic.

Two parameterized types are provably distinct if either of the following conditions hold:

• They are invocations of distinct generic type declarations. • Any of their type arguments are provably distinct.

4.5.1 Type Arguments and Wildcards

Type arguments may be either reference types or wildcards. Wildcards are useful in situations where only partial knowledge about the type parameter is required.

4.5.1 Type Arguments and Wildcards TYPES, VALUES, AND VARIABLES

TypeArguments: < TypeArgumentList >

TypeArgumentList: TypeArgument TypeArgumentList , TypeArgument

TypeArgument: ReferenceType Wildcard

Wildcard: ? WildcardBounds opt

WildcardBounds:

extends ReferenceType super ReferenceType

Example 4.5.1-1. Wildcards

import java.util.Collection; import java.util.ArrayList;

class Test {

static void printCollection(Collection<?> c) {

// a wildcard collection

for (Object o : c) { System.out.println(o); }

public static void main(String[] args) { Collection<String> cs = new ArrayList<String>(); cs.add("hello"); cs.add("world"); printCollection(cs);

Note that using Collection<Object> as the type of the incoming parameter, c , would not be nearly as useful; the method could only be used with an argument expression that had type Collection<Object> , which would be quite rare. In contrast, the use of an unbounded wildcard allows any kind of collection to be used as a parameter.

Here is an example where the element type of an array is parameterized by a wildcard: public Method getMethod(Class<?>[] parameterTypes) { ... }

TYPES, VALUES, AND VARIABLES Type Arguments and Wildcards 4.5.1

Wildcards may be given explicit bounds, just like regular type variable declarations. An upper bound is signified by the following syntax, where B is the bound:

? extends B

Unlike ordinary type variables declared in a method signature, no type inference is required when using a wildcard. Consequently, it is permissible to declare lower

bounds on a wildcard, using the following syntax, where B is a lower bound:

? super B

Example 4.5.1-2. Bounded Wildcards

boolean addAll(Collection<? extends E> c) Here, the method is declared within the interface Collection<E> , and is designed to add

all the elements of its incoming argument to the collection upon which it is invoked. A natural tendency would be to use Collection<E> as the type of c , but this is unnecessarily restrictive. An alternative would be to declare the method itself to be generic:

<T> boolean addAll(Collection<T> c) This version is sufficiently flexible, but note that the type parameter is used only once in the

signature. This reflects the fact that the type parameter is not being used to express any kind of interdependency between the type(s) of the argument(s), the return type and/or throws type. In the absence of such interdependency, generic methods are considered bad style, and wildcards are preferred.

Reference(T referent, ReferenceQueue<? super T> queue); Here, the referent can be inserted into any queue whose element type is a supertype of the

type T of the referent; T is the lower bound for the wildcard.

Two type arguments are provably distinct if one of the following is true: • Neither argument is a type variable or wildcard, and the two arguments are not

the same type. • One type argument is a type variable or wildcard, with an upper bound (from

capture conversion, if necessary) of S ; and the other type argument T is not a type variable or wildcard; and neither | S | <: | T | nor | T | <: | S |.

• Each type argument is a type variable or wildcard, with upper bounds (from capture conversion, if necessary) of S and T ; and neither | S | <: | T | nor | T | <: | S |.

A type argument T 1 is said to contain another type argument T 2 , written T 2 <= T 1 , if the set of types denoted by T 2 is provably a subset of the set of types denoted

4.5.2 Members and Constructors of Parameterized Types TYPES, VALUES, AND VARIABLES

by T 1 under the reflexive and transitive closure of the following rules (where <: denotes subtyping (§4.10)):

• ? extends T <= ? extends S if T <: S • ? super T <= ? super S if S <: T

• T <= T

• T <= ? extends T • T <= ? super T

The relationship of wildcards to established type theory is an interesting one, which we briefly allude to here. Wildcards are a restricted form of existential types. Given a generic

type declaration G <T extends B > , G <?> is roughly analogous to Some X <: B. G<X> . Historically, wildcards are a direct descendant of the work by Atsushi Igarashi and Mirko

Viroli. Readers interested in a more comprehensive discussion should refer to On Variance- Based Subtyping for Parametric Types by Atsushi Igarashi and Mirko Viroli, in the Proceedings of the 16th European Conference on Object Oriented Programming (ECOOP 2002). This work itself builds upon earlier work by Kresten Thorup and Mads Torgersen (Unifying Genericity, ECOOP 99), as well as a long tradition of work on declaration based variance that goes back to Pierre America's work on POOL (OOPSLA 89).

Wildcards differ in certain details from the constructs described in the aforementioned paper, in particular in the use of capture conversion (§5.1.10) rather than the close operation described by Igarashi and Viroli. For a formal account of wildcards, see Wild FJ by Mads Torgersen, Erik Ernst and Christian Plesner Hansen, in the 12th workshop on Foundations of Object Oriented Programming (FOOL 2005).

4.5.2 Members and Constructors of Parameterized Types

Let C be a generic class or interface declaration with type parameters A 1 ,..., A n , and let C <T 1 ,..., T n >

be an invocation of C , where, for 1 ≤ i ≤ n, T i are types (rather than wildcards). Then:

• Let m be a member or constructor declaration (§8.2, §8.8.6) in C , whose type as declared is T .

The type of m in C <T 1 ,..., T n > is T [A 1 :=T 1 ,...,A n :=T n ] .

• Let m be a member or constructor declaration in D , where D is a class extended by C or an interface implemented by C . Let D <U 1 ,..., U k > be the supertype of C <T 1 ,..., T n >

that corresponds to D .

The type of m in C <T 1 ,..., T n > is the type of m in D <U 1 ,..., U k > . If any of the type arguments in the invocation of C are wildcards, then:

TYPES, VALUES, AND VARIABLES Type Erasure 4.6

• The types of the fields, methods, and constructors in C <T 1 ,..., T n > are the types of the fields, methods, and constructors in the capture conversion (§5.1.9) of

C <T 1 ,..., T n > . • Let D be a (possibly generic) class or interface declaration in C . Then the type

of D in C <T 1 ,..., T n > is D where, if D is generic, all type arguments are unbounded wildcards.

This is of no consequence, as it is impossible to access a member of a parameterized type without performing capture conversion (§5.1.10), and it is impossible to use a wildcard type after the keyword new in a class instance creation expression.

The sole exception to the previous paragraph is when a nested parameterized type is used as the expression in an instanceof operator (§15.20.2), where capture conversion is not applied.