Simple Generic Classes
A type parameter is a placeholder written in angle brackets after a class name, and it works much like a formal parameter in a subroutine.
Try it: Stack and Queue
The difference between a stack (last in, first out) and a queue (first in, first out).
How it works
- A stack adds (push) and removes (pop) at the same end, the top — the last item added leaves first.
- A queue adds (enqueue) at the back and removes (dequeue) from the front — the first item added leaves first.
- peek / front look at the next item without removing it.
- Adding to a full structure is an overflow; removing from an empty one is an underflow.
Default run (3 steps): Stack (bottom → top): 4, 7. 2 of 8 slots used. Choose an operation. Example: push 9. … Stack is now: 4, 7, 9. Size 3/8.
Simplified: Fixed capacity of 8 items so overflow can be shown; Python lists and collections.deque grow as needed.
Loading the simulation…
One Queue for Many Element Types
Suppose you want a single queue implementation that can hold strings, integers, or colors, without writing a separate queue class for each element type. A generic class solves this problem by leaving one spot in its definition open. That open spot is called a type parameter, and the class is written so that the same code works no matter which real type fills it.
What do you think happens?
If the placeholder name in a generic class is changed from ItemType to T, does the class behave differently?
Reveal answer
No, the class behaves exactly the same. The name of a type parameter is arbitrary.
The type parameter is only a label used inside the class. Renaming ItemType to T changes how the code reads, not what the class does or how it is used. You will return to this idea when choosing names later in the article.
Before reading on, think about the Queue class as a template. Which parts of it would need a real type name, and which parts would be identical for every element type? Keep your answer in mind, because the next section traces exactly what the placeholder does inside the class.
Reading a Generic Class Header
The header of a generic class is where the placeholder is introduced. The general form is a class name followed by the type parameter in angle brackets. Read the header from left to right. The angle-bracket part is the only place where the placeholder is declared. Everything inside the braces refers back to that name.
When you read a method inside the body, treat ItemType the same way you would treat String or int. It is a type name, but one that has not yet been given a specific value. The header tells you where it is introduced; the body tells you where it is used.
Four Jobs of the Placeholder
Inside the Queue class, the placeholder does four different jobs. It is the return type of dequeue. It is the type of the formal parameter item in enqueue. It is the actual type parameter given to the LinkedList that stores the items, so the internal list is declared as a LinkedList of the placeholder type. The fourth job is less obvious: the class is written only in terms of the placeholder, so it never commits to any particular element type.
- The header declares ItemType once, in angle brackets after the class name.
- The field items is a
LinkedListwhose element type is the placeholder. - The parameter item of enqueue has the placeholder as its type.
- The return type of dequeue is the placeholder.
How a Type Parameter Is Bound
A type parameter behaves like a formal parameter in a subroutine. A subroutine's formal parameter is a stand-in that receives a real value at each call. A type parameter is a stand-in that receives a real type name at each use of the class. In both cases, the same definition is written once and then supplied with concrete material when it is actually used.
The placeholder is replaced by an actual type name when the class is used to declare a variable or create an object. Because of this, one class definition gives you a whole family of parameterized types. The source describes Queue<String>, Queue<Integer>, and Queue<Color> as all valid uses of the same class.
Tracing Queue<String> Through the Class
Now follow one concrete declaration. The code below fills the placeholder with String. Wherever the class body said ItemType, the code is now dealing with String. Nothing in the Queue class was rewritten to make this happen; the same definition is simply used with a different type name.
next holds the value "Ada"- Queue<String> replaces ItemType with String in every place the class uses it.
- enqueue now accepts a String parameter.
- dequeue now returns String, so the result can be assigned to a String variable without any cast.
class Queue<ItemType>
dequeue() returns ItemType
enqueue(ItemType item)
LinkedList<ItemType>ItemType is an open placeholder in the class definition.
Queue<String>
dequeue() returns String
enqueue(String item)
LinkedList<String>The same placeholder is now bound to String everywhere it appeared.
Mistakes Beginners Make with Type Parameters
Common mistake Believing that renaming the type parameter changes what the class does
What it looks likeChanging class Queue<ItemType> to class Queue<Element> and updating every use to match.
Why it failsThe name of a type parameter is arbitrary. The source states that renaming ItemType to T has no effect on the meaning of the class or how it is used.
Do this insteadTreat the name as a readability choice. Pick a name that is clear to the reader of the code.
Common mistake Assuming a generic class is rewritten for each element type
What it looks likeExpecting a separate StringQueue source file to exist after writing Queue<String>.
Why it failsThe class definition stays the same. The placeholder is only replaced by an actual type name at the point of use.
Do this insteadLook for one class definition and many parameterized uses of it.
Common mistake Mixing parameterized types that were bound to different types
What it looks likePassing an Integer value to enqueue on a variable declared as Queue<String>.
Why it failsQueue<String> and Queue<Integer> are distinct types after binding. A String-bound queue expects String items, so an Integer does not fit its enqueue parameter.
Do this insteadMake the value's type match the type that was bound when the variable was declared.
Spotting a Mismatch in a Trace
Trace the following statements step by step. For each step, state what type the placeholder has been replaced with, and say which line would first show a mismatch if one exists.
Given Queue<String> names = new Queue<String>(); followed by names.enqueue("Ada"); and then names.enqueue(42);, identify the type bound to ItemType, the type of the item parameter in the second enqueue call, and the statement where the mismatch appears.
Hints
- Find the angle-bracket type on the declaration line; that is the type ItemType was replaced with.
- Compare the argument 42 with the parameter type that the placeholder became.
- The first enqueue call matches the bound type; the second one does not.
A mismatch shows up at the call site where a value of the wrong type enters the class, not inside the class body. The class body is written against the placeholder and does not change. Checking the declaration and then the first method call that uses the wrong value will locate the problem.
Key Takeaways
- A type parameter is a placeholder written in angle brackets after a class name, and it works much like a formal parameter in a subroutine.
- Inside a generic class, the placeholder can serve as a return type, a parameter type, and the actual type parameter of another generic class such as
LinkedList. - Writing a parameterized type such as Queue<String> replaces the placeholder with an actual type name everywhere it appears, and one class definition yields a family of such types.
- The name of a type parameter is arbitrary and does not change what the class does, so choose a name that is clear to readers.
- A type mismatch shows up where a value of the wrong type enters the class, so trace the declaration and then the method calls that use it.