What are Generics?
Generics in Java allow developers to write type-safe and reusable code. Introduced in Java 5, generics enable you to define classes, interfaces, and methods with type parameters.
Without generics, we would have to rely on casting and lose compile-time safety. Generics solve this problem elegantly.
Why Use Generics?
- Type Safety: Detect errors at compile-time instead of runtime.
- Elimination of Casting: No need for explicit type casting when retrieving elements.
- Code Reusability: Write a single method or class to work with different types.
Syntax of Generics
The basic syntax of generics involves the use of type parameters denoted by angle brackets <>
.
public class Box<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
public class Main {
public static void main(String[] args) {
Box<String> stringBox = new Box<>();
stringBox.setItem("Hello Generics");
System.out.println(stringBox.getItem()); // Outputs: Hello Generics
Box<Integer> intBox = new Box<>();
intBox.setItem(123);
System.out.println(intBox.getItem()); // Outputs: 123
}
}
Here, T
is a type parameter. It can represent any reference type.
Type Parameters
Java conventions for type parameters are as follows:
T
- TypeE
- Element (used in collections like Lists)K
- Key (used in maps)V
- Value (used in maps)N
- Number
Generic Methods
You can also create methods with generics:
public class GenericMethod {
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
public static void main(String[] args) {
String[] strings = {"Apple", "Banana", "Cherry"};
Integer[] numbers = {1, 2, 3};
printArray(strings); // Works with Strings
printArray(numbers); // Works with Integers
}
}
Wildcards in Generics
Wildcards allow flexibility with generics. There are three types of wildcards:
?
- Unbounded wildcard? extends X
- Upper-bounded wildcard? super X
- Lower-bounded wildcard
public static void printList(List<?> list) {
for (Object item : list) {
System.out.println(item);
}
}
public static void main(String[] args) {
List<Integer> intList = Arrays.asList(1, 2, 3);
List<String> strList = Arrays.asList("A", "B", "C");
printList(intList); // Accepts any list
printList(strList); // Accepts any list
}
Bounded Type Parameters
Sometimes, you need to restrict type parameters to a specific class hierarchy:
public static <T extends Number> void printDoubleValue(T number) {
System.out.println(number.doubleValue());
}
public static void main(String[] args) {
printDoubleValue(10); // Works with Integer
printDoubleValue(10.5); // Works with Double
}
Generics and Collections
Generics are extensively used with Java Collections. For example:
List<String> list = new ArrayList<>();
list.add("Java Generics");
list.add("Collections");
for (String item : list) {
System.out.println(item);
}
Conclusion
Generics in Java provide a powerful way to ensure type safety, improve code readability, and eliminate unnecessary casting. By understanding type parameters, wildcards, and their use in collections, developers can write clean, reusable, and robust code.
0 Comments