Generics was introduced in 2004 in Java programming language. Before the introduction of generics, type safety was not available, which caused program to throw errors during runtime. In this tutorial, we will learn why generics are introduced and how to use them in Java. We will also cover wildcard generics with examples.
Why to use Generics in Java?
1. Type Safety
The primary goal of generics is to ensure type safety. As shown below, generics allowed us to check the type mismatch during compile-time rather than run-time. It is nice to check such errors during compile-time. This allows the code to be fixed during compilation process.
Before Java Generics:
//Compiler doesn't know the type of this ArrayList so //it will allow both the additions and the program will //throw an error during runtime. ArrayList arrList = new ArrayList(); arrList.add(101); arrList.add("hello");
After Java Generics:
//Compiler now knows the type of the ArrayList so it will //throw compile-time error, if you try to add any element //to this list which is not an integer ArrayList<Integer> arrList = new ArrayList<Integer>(); arrList.add(101); arrList.add("hello"); //this will throw compilation error
2. No Type Casting required
There is no need to use type casting. As compiler already knows the type of the data returned from a collection such as ArrayList, HashMap etc.
ArrayList<String> arrList = new ArrayList<String>(); arrList.add("hello"); arrList.add("bye"); //Before generics, we had to use typecasting //like this: String s = (String)arrList.get(1); String s = arrList.get(1); //no typecasting required
3. Code reusability
Generics allowed a single class or method to be used for multiple data types. For example: We can create an object of ArrayList class for multiple data types, as shown below. Instead of creating an ArrayList class for a single data type, it is created using generics which allowed us to create object of ArrayList class with the desired data type.
//List of Strings ArrayList<String> names = new ArrayList<String>(); //List of whole numbers ArrayList<Integer> age = new ArrayList<Integer>(); //List of float numbers ArrayList<Float> arrList = new ArrayList<Float>(); //List of characters ArrayList<Character> arrList = new ArrayList<Character>(); ...so on
Types of Generics in Java
1. Generic Class
A generic class is declared with a Type parameter. In the following example, we have a generic class Demo
, we can use this class in any other class by passing a desired type such as Integer, Float, String etc. You cannot pass primitive data types such as int, float, double etc. as parameter T. To understand the difference between int and Integer, float and Float etc. refer my Java Wrapper Class Tutorial.
//Generic Class class Demo<T> { // T is a type, which can accept any type such as //Integer, Double, String etc. T obj; //Constructor which uses the parameter T to //return the object of the passed type Demo(T obj) { this.obj = obj; } public T getObject() { return this.obj; } } // A class that is using generic class class JavaExample { public static void main(String[] args) { // instance of Integer type Demo<Integer> obj1 = new Demo<Integer>(101); System.out.println(obj1.getObject()); // instance of Float type Demo<Float> obj2 = new Demo<Float>(15.55f); System.out.println(obj2.getObject()); // instance of String type Demo<String> obj3 = new Demo<String>("BeginnersBook"); System.out.println(obj3.getObject()); // instance of Character type Demo<Character> obj4 = new Demo<Character>('A'); System.out.println(obj4.getObject()); } }
Output:
2. Generic Method
Similar to Generic class, we can have generic methods that can accept different parameter types.
public class JavaExample{ //generic method public static <T> void printElements(T[] arr) { for (T item : arr){ System.out.print(item+" "); } System.out.println(); } public static void main( String args[] ) { Character[] chArr = {'H', 'E', 'L', 'L', 'O'}; String[] strArr = {"AA", "BB", "CC"}; System.out.println("Calling generic method with char array"); printElements(chArr); System.out.println("Calling generic method with string array"); printElements(strArr); } }
Output:
Type Parameters in Generics
In the above examples, we have seen that the Type parameter T is used. There are several other parameters types that we can use while working with generics. These parameters are:
- T – Type
- E – Element
- K – Key
- V – Value
- N – Number
Example: Generics K and V parameters
The HashMap class is declared with the K and V parameters. Here, first parameter in generics is the type of the Key and the second parameter is the type of the Value. In the following example, the HashMap accepts integer key values and string values.
import java.util.*; public class JavaExample{ public static void main(String args[]){ //HashMap <k, V> where K is the type of key //and V is the type of value HashMap<Integer,String> hMap=new HashMap<>(); hMap.put(101,"Chaitanya"); hMap.put(120,"Carl"); hMap.put(141,"Aditya"); System.out.println("HashMap elements: "); for(Map.Entry mEntry : hMap.entrySet()){ System.out.print("key: "+ mEntry.getKey() + " & Value: "); System.out.println(mEntry.getValue()); } } }
Output:
HashMap elements: key: 101 & Value: Chaitanya key: 120 & Value: Carl key: 141 & Value: Aditya
Wildcard in Java Generics
Instead of defining the specific type such as Integer, String, Character, we can use wildcard (represented by question mark ?). There are three types of wild card we can while working with generics:
- Upper bound wildcards, defined like this
<? extends className>
- Lower bound wildcards
<? super className>
- Non-bounded wildcards
<?>
1. Upper bound wildcards
MyClass <? extends AnotherClass>
Class MyClass
can accept any parameter type, which is a subclass of AnotherClass
. For example: The ArrayList declared like this can accept any parameter type which is a subclass of Number, such as Integer, Double etc.
ArrayList<? extends Number>
Example: In this example, the method addList()
can accept any ArrayList that has a the type which is a subclass of class Number
.
import java.util.ArrayList; public class JavaExample { private static Double addList(ArrayList<? extends Number> numbers) { double sum=0.0; //to store the sum of list elements for(Number num:numbers) { sum += num.doubleValue(); } return sum; } public static void main(String[] args) { ArrayList<Float> listOfNumbers=new ArrayList<Float>(); listOfNumbers.add(1.5f); listOfNumbers.add(2.5f); listOfNumbers.add(3.0f); System.out.println("Sum of list elements: "+addList(listOfNumbers)); ArrayList<Integer> listOfInts=new ArrayList<Integer>(); listOfInts.add(50); listOfInts.add(150); listOfInts.add(250); System.out.println("Sum of list elements: "+addList(listOfInts)); } }
Output:
Sum of list elements: 7.0 Sum of list elements: 450.0
2. Lower bound wildcards
MyClass <? super AnotherClass>
Class MyClass
can accept any parameter type, which is a superclass of AnotherClass
.
Example:
public abstract class Shape { public abstract void draw(Canvas c); } public class Circle extends Shape { private int x, y, radius; public void draw(Canvas c) { ... } } public class Rectangle extends Shape { private int x, y, width, height; public void draw(Canvas c) { ... } }
Now, if any method has a lower bound parameter like this:
MyClass<? super Rectangle>
Then, that method can only accept the objects of MyClass
, which are declared like this:
MyClass<Rectangle> obj1 = new MyClass<Rectangle>(); OR MyClass<Shape> obj2 = new MyClass<Shape>();
3. Non-bounded wildcards
MyClass <?>
It can accept any parameter type.
Example:
import java.util.List; import java.util.ArrayList; public class JavaExample { public static void printElements(List<?> myList) { for(Object obj:myList) { System.out.println(obj); } } public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(101); list.add(201); list.add(301); System.out.println("Integer List:"); printElements(list); List<String> list2 = new ArrayList<>(); list2.add("hello"); list2.add("hi"); list2.add("bye"); System.out.println("String List:"); printElements(list2); } }
Output:
Integer List: 101 201 301 String List: hello hi bye
Conclusion
In this guide, we learned what are generics and how to use them in Java programming language. We also learned wildcard generics with examples. To learn more such in-depth guides, refer Java Tutorial.