Object Types and Class Names
ArrayList<T> is a parameterized type: a single class ArrayList with a type parameter slot that can be filled to form many distinct types such as ArrayList<String> and ArrayList<Color>.
Three Lists, One Class
Suppose one part of a program needs a growable list of names, another needs a growable list of colors, and a third needs a growable list of players in a game. A naive approach would be to write three separate list classes, each identical except for the kind of element it stores. That duplication gets worse as the number of element types grows.
Java offers a better path. A single ArrayList class can be specialized by naming the kind of element it holds. Once you understand how that specialization is written, the same class can serve every one of those needs. This article follows one question: how does a single class produce many distinct types, and what rules govern which types you are allowed to produce?
Reading ArrayList<String> Piece by Piece
The notation ArrayList<String> looks unusual at first, because it seems to contain two names in one. It is best read as two pieces. The part before the angle brackets, ArrayList, names the class. The part inside the angle brackets, String, is a type argument. It tells Java what kind of element this particular ArrayList is meant to hold.
Read left to right, the expression says: take the ArrayList class and fill its type slot with String. The angle brackets are the notation for that filling. Because the slot is what varies, the class name stays the same across every version of the type. The whole expression names a type that is more specific than the bare class name ArrayList.
One Template, Many Types
A useful way to think about this is that the class is a template, and each filled-in form is a concrete type you can actually use. The template is written once. The filled-in types are produced by choosing a type argument. This is why the list of possible types looks large while the number of class definitions stays at one.
The part that stays the same is the class ArrayList, defined in the package java.util, along with its behavior as a growable list. The part that varies is the type argument placed in the slot. Each choice gives a different type, even though all of them come from one class definition.
What do you think happens?
In the type ArrayList<Color>, what is the class name, and what is the type argument?
Reveal answer
The class name is ArrayList, and the type argument is Color.
The part before the angle brackets names the class. The part inside the angle brackets is the type argument that fills the type slot.
Which Type Arguments Are Legal
Not every type can fill the slot. The type parameter must be an object type, such as a class name or an interface name. Primitive types such as int and char cannot fill the slot. So the question to ask about any candidate type argument is whether it names an object type or a primitive type.
| Candidate type argument | Kind of type | Legal in ArrayList<...>? |
|---|---|---|
| String | class name (object type) | Yes |
| Color | class name (object type) | Yes |
| int | primitive type | No, primitives cannot fill the slot |
| char | primitive type | No, primitives cannot fill the slot |
Deciding whether a type argument is legal depends on whether the candidate is an object type.
Declarations and Matching Object Creation
Once a parameterized type has been formed, it behaves like any other type. It can be used to declare variables, and it can be used with the new operator to create objects. The example below uses both: the first line declares a variable whose type is ArrayList<String>, and the second creates a new object of that type and stores it in the variable.
ArrayList<String> on the left declares the variable names with a parameterized type- new
ArrayList<String>() on the right creates an object of that same type - The type argument String appears on both sides and must agree
Checking whether a declaration and creation agree
A programmer writes ArrayList<String> names = new ArrayList<Color>(); Decide whether this statement is valid and explain why.
- 1Identify the declared type
The left side declares a variable of type
ArrayList<String>, so the type argument is String. - 2Identify the created type
The right side creates an object of type
ArrayList<Color>, so the type argument is Color. - 3Compare the type arguments
The two type arguments differ. Java requires the declaration and the object creation to agree when they are written together.
- 4Conclude
The statement is invalid and produces a compile-time error. Changing either side to match the other fixes it.
The statement is illegal because String and Color do not match. Writing ArrayList<String> on both sides makes it valid.
Parameters and Return Types
A parameterized type is not limited to local variables. It can also appear as the type of a formal parameter in a subroutine definition, and it can be the return type of a subroutine. In both roles it describes what the subroutine expects to receive or produce, so the caller and the subroutine share a precise description of the list involved.
ArrayList<Color> after the parameter list is the formal parameter typeArrayList<Color> before the method name is the return type- Both describe the same parameterized type, so the caller and the method agree on the list
Mistakes Beginners Make
Common mistake Reading ArrayList<String> as two unrelated names
What it looks likeAssuming String is a second class that ArrayList is somehow mixed with.
Why it failsThe part before the angle brackets names the class, and the part inside is a type argument that fills the type slot.
Do this insteadRead the expression as the class ArrayList with its type slot filled by String.
Common mistake Thinking each parameterized type needs its own class
What it looks likeWriting a separate NameList class and a separate ColorList class.
Why it failsA single
ArrayListclass with a type parameter slot produces many distinct types.Do this insteadWrite the class once and choose the type argument when you use it.
Common mistake Using a primitive type as the type argument
What it looks likeArrayList<int>Why it failsThe type argument must be an object type, and primitive types such as int and char cannot fill the slot.
Do this insteadUse an object type such as ArrayList<Integer>, where Integer is a class name.
Common mistake Changing the type argument on only one side of an assignment
What it looks likeArrayList<String> names = new ArrayList<Color>();Why it failsThe declaration and the object creation must match exactly when they are written together.
Do this insteadMake both type arguments identical, such as ArrayList<String> on both sides.
Common mistake Forgetting that a parameterized type works in parameters and return types, not only in local variables
Practice Reading Parameterized Types
For each type below, name the class and the type argument, then say whether the type argument is legal: ArrayList<Player>, ArrayList<char>, and ArrayList<String>.
Hints
- Split each expression at the angle brackets.
- Ask whether the candidate type argument is an object type or a primitive type.
- Only object types such as class names can fill the slot.
Write a declaration and an object creation for a list of colors, then a method signature that takes such a list as a parameter and returns it. Make sure the type argument matches in every place it appears.
Hints
- Use Color as the type argument for every
ArrayListyou write. - The declaration and the new expression must use the same type argument.
Key Takeaways
ArrayList<String> is a parameterized type: the class nameArrayListstays fixed, and the type argument String fills the type slot.- One class definition,
ArrayList<T>, produces many distinct types such asArrayList<String>,ArrayList<Color>, andArrayList<Player>. - The type argument must be an object type such as a class or interface name; primitive types such as int and char cannot fill the slot.
- A parameterized type can declare variables, create objects with new, describe formal parameters, and serve as a return type, and the type arguments must match exactly when written together.