Generics
Overview of Java Generics.
Java generics allows to write code that can work with different data types (String, Integer, etc., and user-defined types) without compromising on type safety. It is achieved by the concept of parameterized types.
What are generics?
Generics are basically templates for classes, interfaces, and methods.
These templates use type parameters, represented by letters like T or S, which act as placeholders for specific data types.
When using a generic class or method, provide the actual data type (e.g., Integer, String) to be used, which replaces the type parameter throughout the code.
The Object is the super-class of all other classes, and Object reference can refer to any object. These features lack type safety but Generics add that type of safety feature.
Benefits of using generics
Increased code re-usability: Single generic class/method can be written that can be used with different data types, reducing code duplication.
Improved type safety: The compiler takes care of type safety at compile time, preventing errors like mixing up different data types in the code.
Reduced casting: Generics eliminate the need for explicit type casting, making the code look cleaner and safer.
Types of Java generics
Generic classes:
How to Declare: Generic classes are blueprints/templates for creating objects with a specific data type. They declare one or more type parameters within angle brackets
< >
in the class declaration.
public class Box<T> {
private T data;
// ... methods to access and manipulate data
}
How to Use: Specify the actual data type when creating an instance
Box<Integer> integerBox = new Box<>();
Box<String> stringBox = new Box<>();
Practical Use Case: A generic
Stack
class can work with different types of elements (e.g.,IntegerStack
,StringStack
).
Generic methods:
Similar to generic classes, these methods have type parameters in their signature, enabling them to operate on different data types. For instance, a swap(T a, T b) method can swap elements of any type.
How to Declare: Similar to generic classes, generic method define the behavior of objects using type parameters. They declare one or more type parameters within angle brackets
< >
in the method declaration.
public static <T> void swap(T a, T b) {
T temp = a;
a = b;
b = temp;
}
How to Use: Call the method with specific data types.
swap(10, 20); // Swapping integers
swap("apple", "banana"); // Swapping strings
Practical Use Case: A generic
sort
method can be used to sort arrays of different data types (e.g.,sort(int[] arr)
,sort(String[] arr)
).
Generic interfaces:
These interfaces can also have type parameters, specifying the types of objects they can work with.
How to Declare: Similar to generic classes, generic interfaces define the behavior of objects using type parameters. They specify the types of objects that can implement the interface.
public interface Pair<K, V> {
K getKey();
V getValue();
}
How to Use: Create concrete classes that implement the interface.
public class NameValuePair implements Pair<String, String> {
// ... implementation of methods
}
Practical Use Case: A generic
Map
interface can be used to create different types of maps (e.g.,HashMap<String, Integer>
,TreeMap<Integer, String>
).
Type Erasure
In Java, generics were added to ensure type safety and to ensure that generics won’t cause overhead at runtime, the compiler employs a process known as type erasure on generics at compile time.
Type erasure removes all type parameters and replaces them with their bounds or with Object if the type parameter is unbounded. With this, the bytecode after compilation contains only normal classes, interfaces and methods, ensuring that no new types are produced. Proper casting is applied as well to the Object type at compile time.
Examples
Generic Stack class
public class Stack<T> {
private T[] elements;
private int top;
// ... methods to push, pop, and peek elements
}
public class Main {
public static void main(String[] args) {
Stack<Integer> intStack = new Stack<>();
intStack.push(10);
intStack.push(20);
Stack<String> stringStack = new Stack<>();
stringStack.push("Hello");
stringStack.push("World");
}
}
Generic Sort method
public class Util {
public static <T extends Comparable<T>> void sort(T[] arr) {
// ... sorting algorithm using array elements' compareTo method
}
public static void main(String[] args) {
Integer[] numbers = {3, 1, 4, 2};
String[] fruits = {"apple", "banana", "cherry"};
sort(numbers);
sort(fruits);
}
}
Generic Map Interface
public interface Pair<K, V> {
K getKey();
V getValue();
}
public class NameValuePair implements Pair<String, String> {
private String name;
private String value;
// ... implementation of methods
}
public class Main {
public static void main(String[] args) {
Pair<String, String> nameValue = new NameValuePair();
nameValue.setKey("name");
nameValue.setValue("John Doe");
}
}
Last updated