[post-views]
Generics enable stronger type checks at compile time and can be used to develop robust and reusable code components.
For example, you would like to print the Numbers and Text using a Printer class.
Using a traditional approach, we will have to create 2 classes since we have 2 types of data i.e. Number(Integer) and Text(String).
Create a class NumberPrinter for Printing Numbers
public class NumberPrinter {
private final Integer value;
public NumberPrinter(Integer value) {
this.value = value;
}
public void printData() {
System.out.println("Printing: " + value);
}
}
Create a class TextPrinter for Printing Text Data
public class TextPrinter {
private final String value;
public TextPrinter(String value) {
this.value = value;
}
public void printData() {
System.out.println("Printing: " + value);
}
}
Creating a Driver Class i.e. Printer
public class Printer {
public static void main(String[] args) {
NumberPrinter numberObj = new NumberPrinter(10);
numberObj.printData(); // output = print: 10
TextPrinter textObj = new TextPrinter("Learning Generics");
textObj.printData(); // output = print: Learning Generics
}
}
Here, you can see, there is a code duplication due to only a change in the data types(Integer and String). So, here the data type is only the difference!
So, let’s understand the concept of Generics to avoid code duplication.
Let’s implement the above example using a Generic Printer class.
public class Printer<T> {
private final T value;
public Printer(T value) {
this.value = value;
}
public void printData() {
System.out.println("Printing: " + value);
}
}
To use this Printer class for different types, you simply instantiate it with the desired data type.
Printer<Integer> integerPrinter = new Printer<>(15);
integerPrinter.printData(); // output = print: 15
Printer<String> stringPrinter = new Printer<>("Learning Generics");
stringPrinter.printData(); // output = print: Learning Generics
Explanation
Here, Only one class (Printer) is required to print different data types.
Printer<T>: Here, T is the name of a type parameter contained within the angle bracket (< >) that can be used to declare a type as a common standard.
This name is used as a placeholder for the actual type that will be passed to the Printer when an object is created.
We can create the Printer objects for other data types also like Double/Long. So, the Code reusability is achieved in style.
Printer(T value): This will accept a value of type T
(any type). Whatever type is specified for an instance of Printer.
package genericclass;
public class Box<T> {
private T t; // T stands for "Type"
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<>();
integerBox.set(10);
System.out.println("Box contains: " + integerBox.get());
Box<String> stringBox = new Box<>();
stringBox.set("Hello World");
System.out.println("Box contains: " + stringBox.get());
}
}
Output
Box contains: 10
Box contains: Hello World
Explanation: The Box
class is a generic container for different types of objects. By specifying the type parameter <T>
, it can safely hold any type, ensuring type safety and reducing the need for casts.
package genericclass;
public class ArrayPrinter<T> {
public void printArray(T[] array) {
for (T element : array) {
System.out.print(element + " ");
}
System.out.println();
}
public static void main(String[] args) {
ArrayPrinter<String> stringPrinter = new ArrayPrinter<>();
stringPrinter.printArray(new String[]{"Hello", "World"});
ArrayPrinter<Integer> integerPrinter = new ArrayPrinter<>();
integerPrinter.printArray(new Integer[]{1, 2, 3, 4});
}
}
Output
Hello World
1 2 3 4
Generic classes can accept multiple types also, as demonstrated in the example where it can accept both Integer and String.
The following example accepts both Integer and String.
public class MultiPrinter<T, V> {
private final T value1;
private final V value2;
public MultiPrinter(T value1, V value2) {
this.value1 = value1;
this.value2 = value2;
}
public void printValue() {
System.out.println("print: " +value1 + " : " + value2);
}
}
//Using this class
MultiPrinter<Integer, String> multiPrinter = new MultiPrinter<>(15, "Hi");
multiPrinter.printValue(); // output = print: 15 : Hi
When declaring an instance of a generic type, the type argument passed to the type parameter must be a reference type.
You cannot use a primitive type, such as int or char.
Printer<int> intOb = new Printer<int>(53);
// Error, can't use primitive type
You must be logged in to submit a review.