Generics in Java and Their Implementation
Generics in Java and Their Implementation
In Java programming language, generics are introduced in J2SE 5 for dealing with type-safe objects.
Join the DZone community and get the full member experience.
Join For FreeGenerics in Java
In Java programming, language generics are introduced in J2SE 5 for dealing with type-safe objects. It detects bugs at the compile time by which code is made stable. Any object type is allowed to be stored in the collection before the generic introduction. Now after the generic introduction in the Java programming language, programmers are forced to store particular object types.
Advantages of Java Generics
Three main advantages of using generics are given below:
1. Type-Safety
Generics allow to store of only a single object type. Therefore, different object types are not allowed to be stored in generics.
Any type of object is allowed to be stored without generics.
// declaring a list with the name dataList
List dataList= new ArrayList();
// adding integer into the dataList
dataList.add(10);
// adding string data into the dataList
dataList.add("10");
With generics, we need to tell the object type we want to store.
- Declaring a list with the name dataList:
List<Integer> dataList= new ArrayList();
- Adding integer into the dataList
dataList.add(10);
- Adding string data into the dataList
dataList.add("10"); // but this statement gives compile-time error
2. No Need for Type Casting
Object type casting is not required with generics.
It is required to do casting before a generic introduction.
declaring a list with the name dataList
List dataList= new ArrayList();
adding an element to the dataList
dataList.add("hello");
typecasting
String s = (String) dataList.get(0);
There is no need for object type casting after generics.
// declaring a list with the name dataList
List<String> dataList= new ArrayList<String>();
// adding an element to the dataList
dataList.add("hello");
//typecasting is not required
String s = dataList.get(0);
3. Checking at Compile Time
Issues will not occur at run time as it is checked at the compile time. And according to good programming strategies, problem handling done at compile time is far better than handling done at run time.
// declaring a list with the name dataList
List<String> dataList = new ArrayList<String>();
// adding an element into the dataList
dataList .add("hello");
// try to add an integer in the dataList but this statement will give compile-time error
dataList .add(32);
Syntax:
Generic collection can be used as :
ClassOrInterface<Type>
Example:
An example of how generics are used in java is given below:
ArrayList<String>
Example Program of Java Generics
The ArrayList class is used in this example. But in place of the ArrayList class, any class of collection framework can be used, like Comparator, HashMap, TreeSet, HashSet, LinkedList, ArrayList, etc.
// importing packages
import java.util.*;
// creating a class with the name GenericsExample
class GenericsExample {
// main method
public static void main(String args[]) {
// declaring a list with the name dataList to store String elements
ArrayList < String > dataList = new ArrayList < String > ();
// adding an element into the dataList
dataList.add("hina");
// adding an element into the dataList
dataList.add("rina");
// if we try to add an integer into the dataList then it will give a compile-time error
//dataList.add(32); //compile time error
// accessing element from dataList
String s = dataList.get(1); //no need of type casting
// printing an element of the list
System.out.println("element is: " + s);
// for iterating over the dataList elements
Iterator < String > itr = dataList.iterator();
// iterating and printing the elements of the list
while (itr.hasNext()) {
System.out.println(itr.next());
}
}
}
Output:
element is: rina
hina
rina
Java Generics Example Using Map
In this, we are using a map to demonstrate the generic example. The map allows the data storage in the form of key-value pairs.
// importing packages
import java.util.*;
// creating a class with the name GenericsExample
class GenericsExample {
// main method
public static void main(String args[]) {
// declaring a map for storing keys of Integer type with String values
Map < Integer, String > dataMap = new HashMap < Integer, String > ();
// adding some key value into the dataMap
dataMap.put(3, "seema");
dataMap.put(1, "hina");
dataMap.put(4, "rina");
// using dataMap.entrySet()
Set < Map.Entry < Integer, String >> set = dataMap.entrySet();
// creating an iterator for iterating over the dataMap
Iterator < Map.Entry < Integer, String >> itr = set.iterator();
// iterating for printing every key-value pair of map
while (itr.hasNext()) {
// type casting is not required
Map.Entry e = itr.next();
System.out.println(e.getKey() + " " + e.getValue());
}
}
}
Output:
1 hina
3 seema
4 rina
Generic Class
A generic class is a class that can refer to any type. And here, for creating a particular type of generic class, we are using the parameter of T type.
The declaration of a generic class is much similar to the declaration of a non-generic class, except that the type parameter section is written after the name of the class. Parameters of one or more than one type are allowed in the type parameter section.
A generic class declaration looks like a non-generic class declaration, except that the class name is followed by a type parameter section. As one or more parameters are accepted, so Parameterized types or parameterized classes are some other names for it.
And the example is given below to demonstrate the use and creation of generic classes.
Generic Class Creation
class GenericClassExample < T > {
T object;
void addElement(T object) {
this.object = object;
}
T get() {
return object;
}
}
Here T type represents that it can refer to any type, such as Employee, String, and Integer. The type specified by you for the class is used for data storage and retrieval.
Generic Class Implementation
Let us see an example for a better understanding of generic class usage
// creating a class with the name GenericExample
class GenericExample {
// main method
public static void main(String args[]) {
// using the generic class created in the above example with the Integer type
GenericClassExample < Integer > m = new GenericClassExample < Integer > ();
// calling addElement for the m
m.addElement(6);
// if we try to call addElement with the string type element then it will give a compile-time error
//m.addElement("hina"); //Compile time error
System.out.println(m.get());
}
}
Output:
6
Generic Method
Similar to the generic class, generic methods can also be created. And any type of argument can be accepted by the generic method. The declaration of the generic method is just similar to that of the generic type, but the scope of the type parameter is limited to the method where its declaration has been done. Generic methods are allowed to be both static and non-static.
Let us understand the generic method of Java with an example. Here is an example of printing the elements of an array. Here E is used for representing elements.
// creating a class with the name GenericExample
public class GenericExample {
// creating a generic method for printing the elements of an array
public static < E > void printElements(E[] elements) {
// iterating over elements for printing elements of an array
for (E curElement: elements) {
System.out.println(curElement);
}
System.out.println();
}
// main method
public static void main(String args[]) {
// declaring an array having Integer type elements
Integer[] arrayOfIntegerElements = {
10,
20,
30,
40,
50
};
// declaring an array having character-type elements
Character[] arrayOfCharacterElements = {
'J',
'A',
'V',
'A',
'T',
'P',
'O',
'I',
'N',
'T'
};
System.out.println("Printing an elements of an Integer Array");
// calling generic method printElements for integer array
printElements(arrayOfIntegerElements);
System.out.println("Printing an elements of an Character Array");
// calling generic method printElements for character array
printElements(arrayOfCharacterElements);
}
}
Output:
Printing an elements of an Integer Array
10
20
30
40
50
Printing an elements of an Character Array
J
A
V
A
T
P
O
I
N
T
Wildcard in Java Generics
Wildcard elements in generics are represented by the question mark (?) symbol. And any type is represented by it. If <? extends Number> is written by us, then this means any Number such as (double, float, and Integer) child class. Now the number class method can be called from any of the child classes. Wildcards can be used as a type of local variable, return type, field, or Parameter. But the wildcards can not be used as type arguments for the invocation of the generic method or the creation of an instance of generic.
Let us understand the wildcards in Java generics with the help of the example below given:
// importing packages
import java.util.*;
// creating an abstract class with the name Animal
abstract class Animal {
// creating an abstract method with the name eat
abstract void eat();
}
// creating a class with the name Cat which inherits the Animal class
class Cat extends Animal {
void eat() {
System.out.println("Cat can eat");
}
}
// creating a class with the name Dog which inherits the Animal class
class Dog extends Animal {
void eat() {
System.out.println("Dog can eat");
}
}
// creating a class for testing the wildcards of java generics
class GenericsExample {
//creating a method by which only Animal child classes are accepted
public static void animalEat(List << ? extends Animal > lists) {
for (Animal a: lists) {
//Animal class method calling by the instance of the child class
a.eat();
}
}
// main method
public static void main(String args[]) {
// creating a list of type Cat
List < Cat > list = new ArrayList < Cat > ();
list.add(new Cat());
list.add(new Cat());
list.add(new Cat());
// creating a list of type Dog
List < Dog > list1 = new ArrayList < Dog > ();
list1.add(new Dog());
list1.add(new Dog());
// calling animalEat for list
animalEat(list);
// calling animalEat for list1
animalEat(list1);
}
}
Output:
Cat can eat
Cat can eat
Cat can eat
Dog can eat
Dog can eat
Upper Bounded Wildcards
The main objective of using upper-bounded wildcards is to reduce the variable restrictions. An unknown type is restricted by it to be a particular type or subtype of a particular type. Upper Bounded Wildcards are used by writing a question mark symbol, then extending the keyword if there is a class and implementing a keyword for the interface, and then the upper bound is written.
Syntax of Upper Bound Wildcard
? extends Type.
Example of Upper Bound Wildcard
Let us understand the Upper Bound Wildcard with an example. Here upper bound wildcards are used by us for List<Double> and List<Integer> method writing.
// importing packages
import java.util.ArrayList;
// creating a class with the name UpperBoundWildcardExample
public class UpperBoundWildcardExample {
// creating a method by using upper bounded wildcards
private static Double sum(ArrayList << ? extends Number > list) {
double add = 0.0;
for (Number n: list) {
add = add + n.doubleValue();
}
return add;
}
// main method
public static void main(String[] args) {
// creating a list of integer type
ArrayList < Integer > list1 = new ArrayList < Integer > ();
// adding elements to the list1
list1.add(30);
list1.add(40);
// calling sum method for printing sum
System.out.println("Sum is= " + sum(list1));
// creating a list of double type
ArrayList < Double > list2 = new ArrayList < Double > ();
list2.add(10.0);
list2.add(20.0);
// calling sum method for printing sum
System.out.println("Sum is= " + sum(list2));
}
}
Output:
Sum is= 70.0
Sum is= 30.0
Unbounded Wildcards
Unknown type list is specified by the unbounded wildcards like List<?>.
Example of Unbounded Wildcards
// importing packages
import java.util.Arrays;
import java.util.List;
// creating a class with the name UnboundedWildcardExample
public class UnboundedWildcardExample {
// creating a method displayElements by using Unbounded Wildcard
public static void displayElements(List << ? > list) {
for (Object n: list) {
System.out.println(n);
}
}
// main method
public static void main(String[] args) {
// creating a list of type integer
List < Integer > list1 = Arrays.asList(6, 7, 8);
System.out.println("printing the values of integer list");
// calling displayElements for list1
displayElements(list1);
// creating a list of type string
List < String > list2 = Arrays.asList("six", "seven", "eight");
System.out.println("printing the values of string list");
// calling displayElements for list2
displayElements(list2);
}
}
Output:
printing the values of integer list
6
7
8
printing the values of string list
six
seven
eight
Lower Bounded Wildcards
Lower Bounded Wildcards are used to restrict the unknown type to be a particular type or the supertype of the particular type. Lower Bounded Wildcards are used by writing a question mark symbol followed by the keyword super, then writing the lower bound.
Syntax of Lower Bound Wildcard
? super Type.
Example of Lower Bound Wildcard
// importing packages
import java.util.*;
// creating a class with the name LowerBoundWildcardExample
public class LowerBoundWildcardExample {
// creating a method by using upper bounded wildcards
private static void displayElements(List << ? super Integer > list) {
for (Object n: list) {
System.out.println(n);
}
}
// main method
public static void main(String[] args) {
// creating a list of type integer
List < Integer > list1 = Arrays.asList(6, 7, 8);
System.out.println("printing the values of integer list");
// calling displayElements for list1
displayElements(list1);
// creating a list of type string
List < Number > list2 = Arrays.asList(8.0, 9.8, 7.6);
System.out.println("printing the values of string list");
// calling displayElements for list2
displayElements(list2);
}
}
Output:
printing the values of integer list
6
7
8
printing the values of string list
8.0
9.8
7.6
Conclusion
- After the generic introduction in the Java programming language, programmers are forced to store particular object types.
- Type safety, No need for type casting, and Checking at compile time are Three main advantages of using generics.
- A generic class is a class that can refer to any type.
- Similar to the generic class, generic methods can also be created. And any type of argument can be accepted by the generic method.
- Wildcard elements in generics are represented by the question mark (?) symbol.
- Upper Bounded, Lower Bounded, and Unbounded are three types of wildcards in Java generic.
Opinions expressed by DZone contributors are their own.
{{ parent.title || parent.header.title}}
{{ parent.tldr }}
{{ parent.linkDescription }}
{{ parent.urlSource.name }}