Lab Session 13: Generics in Java
Lab Session 13: Generics in Java
BS(SE) 2021
CSS 1042
Department of CS and SE
A class is said to be Generic if it declares one or more type variables. These variable types are known
as the type parameters of the Java Class.
Generic methods are much similar to generic classes. They differ from each other in only one aspect
that the scope or type information is inside the method only. Generic methods introduce their own
type parameters.
Let’s understand this with an example.
Generic Method Example
public class test {
public < E > void showArray(E[] s) {
for (E x: s)
System.out.println(x);
}
public static void main(String[] args) {
test Obj = new test();
String name[] = new String[] {
"Sachin",
"Virat",
"Dhoni"
};
Integer roll[] = {
10,
23,
44
};
Obj.showArray(name);
Obj.showArray(roll);
}
}
Output
Sachin
Virat
Dhoni
10
23
44
Object Oriented Programming
BS(SE) 2021
CSS 1042
Department of CS and SE
In this example, type parameter <E> gets replaced by the string when called with string array and by
integer when called by integer array. The type parameter is placed before the return type of the
method.
We can have more than one parameter type in a method or class. Example:
public class test {
Public < E, N > void showArray(E x, N y) {
System.out.println(x);
System.out.println(y);
}
Public static void main(String[] args) {
test obj = new test();
obj.showArray("John Doe", 43);
}
}
Output:
John Doe
43
Java example to illustrate the use of Java Generics
package com.dataflair.javagenerics;
import java.io.*;
import java.util.*;
class GenericClass<T>
{
//This is a generic class definition. The type is T as mentioned.
GenericClass()
{
System.out.println("The generic class is declared now. You can use it well");
}
public void methodgeneric(T obj)
{
System.out.println("The type of the object that this class now contains is
"+obj.getClass().getSimpleName());
}
}
public class GenericsExample {
public static void main(String[] args) {
GenericClass<Integer> test=new GenericClass<>();
Integer a=5;
test.methodgeneric(a);
//Now we use the same class but with a different datatype.
GenericClass<String> teststring = new GenericClass<>();
String s="DataFlair is the best";
teststring.methodgeneric(s);
}
}
Object Oriented Programming
BS(SE) 2021
CSS 1042
Department of CS and SE
Output
The generic class is declared now. You can use it well
The type of the object that this class now contains is Integer
The generic class is declared now. You can use it well
The type of the object that this class now contains is String
If you observe carefully, we set the value of the same class with different datatypes. That is the power
of generics.
It allows you to work with different datatypes without worrying about the repercussions and different
rules of different data types.
Now let us see what the program is doing step by step.
● As soon as the main function calls the generic type object the constructor gets called and you
can see the line “The generic class is declared now. You can use it well”
● Now, as the class is generic in nature, it allows the Integer type object passed to its methods
and prints the class name.
● You can easily identify the class name and the type of the variable passed to the method by
the .getClass() method. Simple!
● Now we pass a different datatype but thanks to generics the method behaves the same way!
Generic Interface
An interface in Java refers to the abstract data types. They allow Java collections to be manipulated
independently from the details of their representation. Also, they form a hierarchy in object-oriented
programming languages. Let’s understand how generic type can be applied to interfaces in Java.
Example
public class GenericInterfaceExample {
public static void main(String args[]) {
Integer intOfArray[] = { 3, 6, 2, 8, 6 };
Character charOfArray[] = { 'A', 'r', 'V', 'w' };
String strOfArray[] = {"abc", "xyz", "pqr"};
MinMaxImpl<Integer> intMinMax = new MinMaxImpl<Integer>(intOfArray);
MinMaxImpl<Character> charMinMax = new MinMaxImpl<Character>(charOfArray);
MinMaxImpl<String> strMinMax = new MinMaxImpl<String>(strOfArray);
System.out.println("Max value in intOfArray: " + intMinMax.max());
System.out.println("Min value in intOfArray: " + intMinMax.min());
System.out.println("Max value in charOfArray: " + charMinMax.max());
System.out.println("Min value in charOfArray: " + charMinMax.min());
System.out.println("Max value in strOfArray: " + strMinMax.max());
System.out.println("Min value in strOfArray: " + strMinMax.min());
}
}
interface MinMax<T extends Comparable<T>> {
T min();
T max();
}
class MinMaxImpl<T extends Comparable<T>> implements MinMax<T> {
Object Oriented Programming
BS(SE) 2021
CSS 1042
Department of CS and SE
T[] vals;
MinMaxImpl(T[] o) {
vals = o;
}
public T min() {
T v = vals[0];
for (int i = 1; i < vals.length; i++) {
if (vals[i].compareTo(v) < 0) {
v = vals[i];
}
}
return v;
}
public T max() {
T v = vals[0];
for (int i = 1; i < vals.length; i++) {
if (vals[i].compareTo(v) > 0) {
v = vals[i];
}
}
return v;
}
}
Output
Max value in intOfArray: 8
Min value in intOfArray: 2
Max value in charOfArray: w
Min value in charOfArray: A
Max value in strOfArray: xyz
Min value in strOfArray: abc
Generic Constructor
A constructor can be generic, even if its class is not. A generic constructor is a constructor that has at
least one parameter of a generic type.
Example
public class Pair<T> {
private T first;
private T second;
}
However, when you instantiate a generic class, you do specify the type in angular brackets when
writing the constructor name.
Pair<String> aPair = new Pair<String>("Happy", "Day"); // Create a pair of String object
Pair<Integer> bPair = new Pair<Integer>(2, 3); // Create a pair of Integer objects
Bounded Types
When you want to specify a particular type which is a subclass of a particular class you can use
Bounded Types. Bounded types allow you to restrict the data type of the collection. For example, if
you write a generic with the extends keyword then you can use bounded types.
E.g.: <T extends A>
If A is Number class then you can use all types of data which are of type Integer, Float, Double, etc.
Java program to illustrate bounded types in Java:
package com.dataflair.javagenerics;
class GenericTypeClass<T extends Number>
{
//This is a class where you can only use generic objects of classes
//which are a subclass of Number that is Integer, Float etc.
GenericTypeClass(T obj)
{
System.out.println(obj.getClass().getName());
}
}
public class Simple{
public static void main(String[]args)
{
Integer a = 10;
GenericTypeClass<Integer> obj = new GenericTypeClass<>(a);
String s="DataFlair";
//GenericTypeClass<String> obj2=new GenericTypeClass<>(a);
}
}
Output
java.lang.Integer
If you try to remove the commented line the compiler will throw an error because the String class
does not extend the Number class.
Wildcards
With wildcard, we can further enhance the usage of generics. We use a wildcard when we want to
make a method or class that can accept any kind of data or collection or when we want to impose
some restrictions or relaxation on a variable.
Object Oriented Programming
BS(SE) 2021
CSS 1042
Department of CS and SE
From the syntax, it’s easy enough to guess that "? extends T" means that there's a class that extends
the generic type T, but what is "? extends T "? Let’s answer this question with a code-driven
explanation.
Let’s suppose we’re writing a staff management application. We’ve got a Person class in our domain,
and it has two subclasses: an Employee and a Partner. One common operation you might wish to
perform is to save these objects into a database, and maybe write a method like this:
public void saveAll(final List<Person> people)
{
// Saves people into a database ...
}
What could go wrong with that? It’s so nice and simple, and we can use it like this:
List<People> people = new ArrayList<>();
people.add(donDraper);
people.add(peggyOlson);
saver.saveAll(people);
But wait. Let’s step back for a minute. We actually want to be able to save more than just lists of
people. We have Employees and Partners as well, and we want to be able to save lists of each. If we
try to write this code, we get a compile error on the line highlighted in red.:
List<Partner> people = new ArrayList<>();
people.add(donDraper);
people.add(bertCooper);
saver.saveAll(people);
Wildcards let us increase the flexibility of our generic type parameters by allowing us to pass in
subclasses and superclasses. You can spot them in code thanks to the way they look (? extends Foo
or ? super Bar). We could change the original method’s signature like this:
public void saveAll(final List<? extends Person> people)
{
// Saves people into a database ...
}
And now we can pass in variables that have types like List<Partner> or List<Employee>, as well as
List<Person> as an argument to our saveAll method. Problem solved! It’s also worth noting that
extends doesn’t just allow us to use subclasses of a class, but also implementers of an interface as
well.
Upper-bound Wildcards
It provides the freedom to the variable by either making it a specific type or subtype of the specific
type. In Java, it is declared by using the? keyword followed by the extend keyword. Extend keyword
is used to provide access to the subtypes of the specific type to the methods. Example list<? extends
Number> can be used to extend the type Number along with its subtype (Integer, Double etc.)
whereas list<Numbers> restrict user with a list of type number only. Observe the below code for
better understanding.
Object Oriented Programming
BS(SE) 2021
CSS 1042
Department of CS and SE
import java.util.Array;
import java.util.List;
public class UpperBoundWildcard {
private static Double SumOfElements(ArrayList < ? extends Number > num) {
double sum = 0.0;
for (Number n: num) {
sum = sum + n.doubleValue();
}
return sum;
}
public static void main(String[] args) {
Unbounded Wildcards
Unbounded wild cards are used when we don’t know what type of list will come as input. In that case,
we make our method using list<?> which means that list can be of any type. We use it when we want
our method independent from parameter type. Example:
import java.util.Arrays;
import java.util.List;
public class UnboundedWildcard {
public static void show(List < ? > list) {
for (Object o: list) {
System.out.println(o);
}
}
public static void main(String[] args) {
List < Integer > ListOfIntegers = Arrays.asList(5, 10, 15);
System.out.println("List of Integer values-");
show(ListOfIntegers);
List < String > ListOfString = Arrays.asList("Virat", "Dhoni", "Dravid");
System.out.println("List of String values");
show(ListOfString);
}
}
Object Oriented Programming
BS(SE) 2021
CSS 1042
Department of CS and SE
Output
List of Integer values
5
10
15
List of String values
Virat
Dhoni
Dravid
The above code worked well for both types of lists i.e. integer and string. This is the advantage of
unbounded wildcard.
Lower-bound Wildcards
We use lower bound wildcards when we want to work on a specific type or superclass of that type like
integers and its superclass numbers. It is used by declaring wildcard symbol ? followed by the super
keyword. Consider the following example:
import java.util.Arrays;
import java.util.List;
public class LowerBoundWildcard {
public static void show(List < ? super Integer > list) {
for (Object n: list) {
System.out.println(n);
}
}
public static void main(String[] args) {
List < Integer > ListOfIntegres = Arrays.asList(10, 20, 30);
System.out.println("Showing the Integer values");
show(ListOfIntegres);
List < Number > ListOfNumbers = Arrays.asList(100.0, 200.0, 300.0);
System.out.println("Showing the Number values");
show(ListOfNumbers);
}
}
Output
Showing the Integer values
10
20
30
Showing the Number values
100.0
200.0
300.0
In the above code, we declared the list type be integers but by using the super keyword we made the
method acceptable for superclass of integers. That’s why we were able to print double values too
because superclass of integers i.e., numbers contains double class.
Object Oriented Programming
BS(SE) 2021
CSS 1042
Department of CS and SE
Exercises
1. Given the following classes:
class Shape { /* ... */ }
class Circle extends Shape { /* ... */ }
class Rectangle extends Shape { /* ... */ }
2. Consider the following code, where the 'printarray()' method is used to print out arrays of
different types:
Integer [] intArry = {1, 2, 3, 4, 5 };
Double [] doubArry = {1.1, 2.2, 3.3, 4.4};
Character [] charArray = {'H','E','L', 'L', 'O' };
String [] strArray = {“once”, “upon”, “a”, “time” };
printarray(intArry);
printarray(doubArry);
printarray(charArray);
printarray(strArray);
Write a JAVA program with a main method that includes the example code, above. Implement
the static printarray() method using Generic programming technique so that you have a single
method supporting all the types and maintain type safety.
3. Design a class that acts as a library for the following kinds of media: book, video, and newspaper.
Provide one version of the class that uses generics and one that does not.