Introduction to Generics
Part of the Object Oriented Programming section of Coddy's Java journey — lesson 53 of 87.
Imagine you need to create a class that stores a value and retrieves it later. Without generics, you'd have to write separate classes for each type—one for Integer, one for String, one for Double, and so on. This leads to code duplication and maintenance headaches.
Generics solve this problem by allowing you to write classes and methods that work with any type, while still maintaining type safety. You define a placeholder (called a type parameter) that gets replaced with an actual type when you use the class:
// Without generics - uses Object, requires casting
List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0); // Manual casting needed
// With generics - type-safe, no casting
List<String> list = new ArrayList<String>();
list.add("Hello");
String s = list.get(0); // No casting neededThe angle brackets <T> denote a type parameter. When you write List<String>, you're telling the compiler that this list will only contain strings. If you try to add an integer, the compiler catches the error immediately rather than failing at runtime.
Generics provide two key benefits: they eliminate the need for explicit casting, and they catch type errors at compile time instead of runtime. This makes your code both safer and cleaner. In the following lessons, we'll explore how to create your own generic classes and methods.
Challenge
EasyLet's build a simple storage system that demonstrates the power of generics by comparing the old way (using Object with casting) versus the new way (using generics with type safety).
You'll create three files to see the difference firsthand:
OldBox.java: Create a class that stores values the pre-generics way. Your OldBox should have a private fieldcontentof typeObject. Include a constructor that accepts an Object and stores it, and agetContent()method that returns the Object. This approach works but requires casting when retrieving values.GenericBox.java: Now create the modern, type-safe version using generics. Your GenericBox should use a type parameterTin its declaration. It needs a private fieldcontentof typeT, a constructor that accepts aTvalue, and agetContent()method that returns typeT. No casting needed when using this class!Main.java: Demonstrate both approaches side by side. You'll receive two inputs: a word (String) and a number (integer).First, use the old approach: create an OldBox storing the word, then retrieve it with a cast to String and print:
OldBox (with cast): [value]Next, use the generic approach: create a
GenericBox<String>storing the same word, retrieve it without casting, and print:GenericBox (no cast): [value]Then show generics working with integers: create a
GenericBox<Integer>storing the number, retrieve it, and print:GenericBox Integer: [value]Finally, print a blank line followed by:
Type safety: Generics catch errors at compile time!
You will receive two inputs in order: a word (String) and a number (integer as String, which you'll parse).
Notice the key difference: with OldBox, you must cast (String) box.getContent() and hope you got the type right. With GenericBox, the compiler knows the type and no casting is needed. This is the core benefit of generics—type safety without the casting hassle!
Cheat sheet
Generics allow you to write classes and methods that work with any type while maintaining type safety. They use type parameters (placeholders) that get replaced with actual types when the class is used.
Without generics (using Object):
List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0); // Manual casting requiredWith generics (type-safe):
List<String> list = new ArrayList<String>();
list.add("Hello");
String s = list.get(0); // No casting neededCreating a generic class:
public class GenericBox<T> {
private T content;
public GenericBox(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}Using a generic class:
GenericBox<String> stringBox = new GenericBox<String>("Hello");
String value = stringBox.getContent(); // No casting
GenericBox<Integer> intBox = new GenericBox<Integer>(42);
Integer number = intBox.getContent(); // Type-safeThe angle brackets <T> denote a type parameter. Benefits include: no explicit casting needed and type errors caught at compile time instead of runtime.
Try it yourself
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String word = scanner.nextLine();
int number = Integer.parseInt(scanner.nextLine());
// TODO: Create an OldBox storing the word
// Retrieve with cast to String and print: "OldBox (with cast): [value]"
// TODO: Create a GenericBox<String> storing the word
// Retrieve without casting and print: "GenericBox (no cast): [value]"
// TODO: Create a GenericBox<Integer> storing the number
// Retrieve and print: "GenericBox Integer: [value]"
// TODO: Print a blank line, then print:
// "Type safety: Generics catch errors at compile time!"
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsFields (Attributes)Constructor MethodConstructor OverloadingRecap - Simple Calculator4Inheritance
Basic Inheritance (extends)The super KeywordMethod Overriding (@Override)Constructor ChainingThe Object ClassSingle & Multilevel InheritWhy No Multi Class InheritRecap - Employee Hierarchy7Special Methods & Object Class
toString() Methodequals() and hashCode()clone() MethodcompareTo() and ComparableComparator InterfaceRecap - Custom Sorting2Access Modifiers & Encapsulate
Access Levels OverviewGetter and Setter MethodsInformation HidingThe final KeywordRecap - Bank Account Manager5Polymorphism
Method Overloading BasicsMethod Overriding (Run-Time)Upcasting and DowncastingThe instanceof OperatorAbstract Classes and MethodsRecap - Shape Calculator8Advanced OOP Concepts
Composition vs InheritanceAggregation vs CompositionInner Nested & Anonymous ClassEnums and Enum MethodsRecords (Java 16+)Sealed Classes (Java 17+)3Class Props & Static Member
Instance vs Static VariablesStatic MethodsStatic BlocksConstants (static final)Recap - Counter & Utility6Interfaces & Abstract Classes
Introduction to InterfacesImplementing InterfacesMulti Interface ImplemenDefault & Static in InterfaceAbstract Classes vs InterfacesFunctional InterfacesRecap - Payment System9Generics
Introduction to GenericsGeneric ClassesGeneric MethodsBounded Type ParametersWildcards (?, extends, super)Recap - Generic Container