Advanced JAVA ****** 23CSP512
Advanced JAVA
23CSP512
MODULE 3
Generics:
What are Generics? A Simple Generic Example, A Generic Class with Two Type
Parameters, The General Form of a Generic Class, Bounded Types, Using Wildcard
Arguments, Creating a Generic Method, Generic Interfaces, Generic Class Hierarchies,
Type Inference with Generics, Some Generic Restrictions.
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 1
Advanced JAVA ****** 23CSP512
Generics in Java
Generics means parameterized types. The idea is to allow a type (like Integer, String, etc., or user-
defined types) to be a parameter to methods, classes, and interfaces. Generics in Java allow us to create
classes, interfaces, and methods where the type of the data is specified as a parameter. If we use generics,
we do not need to write multiple versions of the same code for different data types.
Why Use Generics?
Before Generics, the Java developers used Object to store any type of data. The Object is the superclass
of all other classes, and an Object reference can refer to any object. These features lack type safety. For
example, adding an Integer to a list of String would not show an error until runtime. Generics add that
type of safety feature. We will discuss that type of safety feature in later examples.
Generics in Java are similar to templates in C++. For example, classes like HashSet, ArrayList, HashMap,
etc., use generics very well. There are some fundamental differences between the two approaches to
generic types.
Types of Java Generics
1. Generic Method: A generic Java method takes a parameter and returns some value after performing a
task. It is exactly like a normal function, however, a generic method has type parameters that are cited by
an actual type. This allows the generic method to be used in a more general way. The compiler takes care
of the type of safety, which enables programmers to code easily since they do not have to perform long,
individual type castings.
2. Generic Classes: A generic class is implemented exactly like a non-generic class. The only difference
is that it contains a type parameter section. There can be more than one type of parameter, separated by a
comma. The classes that accept one or more parameters are known as parameterized classes or
parameterized types.
Generic Class
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 2
Advanced JAVA ****** 23CSP512
A generic class is a class that can operate on objects of different types using a type parameter. Like C++,
we use <> to specify parameter types in generic class creation. To create objects of a generic class, we use
the following syntax:
// To create an instance of generic class
BaseType <Type> obj = new BaseType <Type>()
Note: In Parameter type, we can not use primitives like "int", "char", or "double". Use wrapper classes
like Integer, Character, etc.
Example:
// Java program to show working of user defined
// Generic classes
// We use < > to specify Parameter type
class Test<T> {
// An object of type T is declared
T obj;
Test(T obj) { [Link] = obj; } // constructor
public T getObject() { return [Link]; }
// Driver class to test above
class Geeks {
public static void main(String[] args)
// instance of Integer type
Test<Integer> iObj = new Test<Integer>(15);
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 3
Advanced JAVA ****** 23CSP512
[Link]([Link]());
// instance of String type
Test<String> sObj
= new Test<String>("GeeksForGeeks");
[Link]([Link]());
Output
15
GeeksForGeeks
We can also pass multiple Type parameters in Generic classes.
Example: Generic Class with Multiple Type Parameters
// Java program to show multiple
// type parameters in Java Generics
// We use < > to specify Parameter type
class Test<T, U>
T obj1; // An object of type T
U obj2; // An object of type U
// constructor
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 4
Advanced JAVA ****** 23CSP512
Test(T obj1, U obj2)
this.obj1 = obj1;
this.obj2 = obj2;
// To print objects of T and U
public void print()
[Link](obj1);
[Link](obj2);
// Driver class to test above
class Geeks
public static void main (String[] args)
Test <String, Integer> obj =
new Test<String, Integer>("GfG", 15);
[Link]();
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 5
Advanced JAVA ****** 23CSP512
Output
GfG
15
Generic Method
We can also write generic methods that can be called with different types of arguments based on the type
of arguments passed to the generic method. The compiler handles each method.
Example:
// Java program to show working of user defined
// Generic functions
class Geeks {
// A Generic method example
static <T> void genericDisplay(T element)
[Link]([Link]().getName()
+ " = " + element);
// Driver method
public static void main(String[] args)
// Calling generic method with Integer argument
genericDisplay(11);
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 6
Advanced JAVA ****** 23CSP512
// Calling generic method with String argument
genericDisplay("GeeksForGeeks");
// Calling generic method with double argument
genericDisplay(1.0);
Output
[Link] = 11
[Link] = GeeksForGeeks
[Link] = 1.0
Limitations of Generics
1. Generics Work Only with Reference Types
When we declare an instance of a generic type, the type argument passed to the type parameter must be a
reference type. We cannot use primitive data types like int, char.
Test<int> obj = new Test<int>(20);
The above line results in a compile-time error that can be resolved using type wrappers to encapsulate a
primitive type.
But primitive type arrays can be passed to the type parameter because arrays are reference types.
ArrayList<int[]> a = new ArrayList<>();
2. Generic Types Differ Based on their Type Arguments
During compilation, generic type information is erased which is also known as type erasure.
Example:
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 7
Advanced JAVA ****** 23CSP512
// Java program to show working
// of user-defined Generic classes
// We use < > to specify Parameter type
class Test<T> {
// An object of type T is declared
T obj;
Test(T obj) { [Link] = obj; } // constructor
public T getObject() { return [Link]; }
// Driver class to test above
class Geeks {
public static void main(String[] args)
// instance of Integer type
Test<Integer> iObj = new Test<Integer>(15);
[Link]([Link]());
// instance of String type
Test<String> sObj
= new Test<String>("GeeksForGeeks");
[Link]([Link]());
iObj = sObj; // This results an error
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 8
Advanced JAVA ****** 23CSP512
Output:
error:
incompatible types:
Test cannot be converted to Test
Explanation: Even though iObj and sObj are of type Test, they are the references to different types
because their type parameters differ. Generics add type safety through this and prevent errors.
Type Parameter Naming Conventions
The type parameters naming conventions are important to learn generics thoroughly. The common type
parameters are as follows:
T: Type
E: Element
K: Key
N: Number
V: Value
Advantages of Generics
Code Reusability: We can write a method, class, or interface once and use it with any type.
Type Safety: Generics ensure that errors are detected at compile time rather than runtime, promoting
safer code.
No Need for Type Casting: The compiler automatically handles casting, removing the need for
explicit type casting when retrieving data.
Code Readability and Maintenance: By specifying types, code becomes easier to read and maintain.
Generic Algorithms: Generics allow for the implementation of algorithms that work across various
types, promoting efficient coding practices.
Disadvantages of Generics
Complexity: For beginners, understanding concepts like wildcards (? extends, ? super) can be difficult.
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 9
Advanced JAVA ****** 23CSP512
Performance Overhead: Type erasure causes some overhead as generic types are converted
to Object during runtime.
No Support for Primitive Types: Generics only work with reference types, requiring the use of
wrapper classes like Integer or Double for primitives.
Limited Reflection: Type erasure limits how much you can use reflection with generics since type
information is not available at runtime.
Benefits of Generics
Programs that use Generics has got many benefits over non-generic code.
1. Code Reuse: We can write a method/class/interface once and use it for any type we want.
2. Type Safety: Generics make errors to appear compile time than at run time (It's always better to know
problems in your code at compile time rather than making your code fail at run time).
Suppose you want to create an ArrayList that store name of students, and if by mistake the programmer
adds an integer object instead of a string, the compiler allows it. But, when we retrieve this data from
ArrayList, it causes problems at runtime.
Example: Without Generics
// Java program to demonstrate that NOT using
// generics can cause run time exceptions
import [Link].*;
class Geeks
public static void main(String[] args)
// Creatinga an ArrayList without any type specified
ArrayList al = new ArrayList();
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 10
Advanced JAVA ****** 23CSP512
[Link]("Sweta");
[Link]("Gudly");
[Link](10); // Compiler allows this
String s1 = (String)[Link](0);
String s2 = (String)[Link](1);
// Causes Runtime Exception
String s3 = (String)[Link](2);
Output :
Exception in thread "main" [Link]:
[Link] cannot be cast to [Link]
at [Link]([Link])
Here, we get runtime error.
How do Generics Solve this Problem?
When defining ArrayList, we can specify that this list can take only String objects.
Example: With Generics
// Using Java Generics converts run time exceptions into
// compile time exception.
import [Link].*;
class Geeks
public static void main(String[] args)
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 11
Advanced JAVA ****** 23CSP512
// Creating a an ArrayList with String specified
ArrayList <String> al = new ArrayList<String> ();
[Link]("Sweta");
[Link]("Gudly");
// Now Compiler doesn't allow this
[Link](10);
String s1 = (String)[Link](0);
String s2 = (String)[Link](1);
String s3 = (String)[Link](2);
Output:
15: error: no suitable method found for add(int)
[Link](10);
3. Individual Type Casting is not needed: If we do not use generics, then, in the above example, every
time we retrieve data from ArrayList, we have to typecast it. Typecasting at every retrieval operation is a
big headache. If we already know that our list only holds string data, we need not typecast it every time.
Example:
// We don't need to typecast individual members of ArrayList
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 12
Advanced JAVA ****** 23CSP512
import [Link].*;
class Geeks {
public static void main(String[] args)
// Creating a an ArrayList with String specified
ArrayList<String> al = new ArrayList<String>();
[Link]("Sweta");
[Link]("Gudly");
// Typecasting is not needed
String s1 = [Link](0);
String s2 = [Link](1);
4. Generics Promotes Code Reusability: With the help of generics in Java, we can write code that will
work with different types of data. For example,
Let's say we want to Sort the array elements of various data types like int, char, String etc. Basically we
will be needing different functions for different data types. For simplicity, we will be using Bubble sort.
But by using Generics, we can achieve the code reusability feature.
Example: Generic Sorting
public class Geeks {
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 13
Advanced JAVA ****** 23CSP512
public static void main(String[] args)
Integer[] a = { 100, 22, 58, 41, 6, 50 };
Character[] c = { 'v', 'g', 'a', 'c', 'x', 'd', 't' };
String[] s = { "Amiya", "Kuna", "Gudly", "Sweta","Mama", "Rani", "Kandhei" };
[Link]("Sorted Integer array: ");
sort_generics(a);
[Link]("Sorted Character array: ");
sort_generics(c);
[Link]("Sorted String array: ");
sort_generics(s);
public static <T extends Comparable<T> > void sort_generics(T[] a)
//As we are comparing the Non-primitive data types
//we need to use Comparable class
//Bubble Sort logic
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 14
Advanced JAVA ****** 23CSP512
for (int i = 0; i < [Link] - 1; i++) {
for (int j = 0; j < [Link] - i - 1; j++) {
if (a[j].compareTo(a[j + 1]) > 0) {
swap(j, j + 1, a);
// Printing the elements after sorted
for (T i : a)
[Link](i + ", ");
[Link]();
public static <T> void swap(int i, int j, T[] a)
T t = a[i];
a[i] = a[j];
a[j] = t;
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 15
Advanced JAVA ****** 23CSP512
Output
Sorted Integer array: 6, 22, 41, 50, 58, 100,
Sorted Character array: a, c, d, g, t, v, x,
Sorted String array: Amiya, Gudly, Kandhei, Kuna, Mama, Rani, Sweta,
Here, we have created a generics method. This same method can be used to perform operations on integer
data, string data, and so on.
Tip: If you are new to Java, start practicing Generics with basic examples like generic Box, generic Pair,
and generic methods.
Bounded Type
There may be times when you want to restrict the types that can be used as type arguments in a
parameterized type. For example, a method that operates on numbers might only want to accept
instances of Numbers or their subclasses. This is what bounded type parameters are for.
Sometimes we don’t want the whole class to be parameterized. In that case, we can create a
Java generics method. Since the constructor is a special kind of method, we can use generics type in
constructors too.
Suppose we want to restrict the type of objects that can be used in the parameterized type. For
example, in a method that compares two objects and we want to make sure that the accepted objects
are Comparables.
The invocation of these methods is similar to the unbounded method except that if we will try to use
any class that is not Comparable, it will throw compile time error.
How to Declare a Bounded Type Parameter in Java?
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 16
Advanced JAVA ****** 23CSP512
1. List the type parameter's name,
2. Along with the extends keyword
3. And by its upper bound. (which in the below example c is A.)
Syntax
<T extends superClassName>
Note that, in this context, extends is used in a general sense to mean either “extends” (as in classes).
Also, This specifies that T can only be replaced by superClassName or subclasses of superClassName.
Thus, a superclass defines an inclusive, upper limit.
Let’s take an example of how to implement bounded types (extend superclass) with generics.
// This class only accepts type parameters as any class
// which extends class A or class A itself.
// Passing any other type will cause compiler time error
class Bound<T extends A>
private T objRef;
public Bound(T obj){
[Link] = obj;
public void doRunTest(){
[Link]();
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 17
Advanced JAVA ****** 23CSP512
class A
public void displayClass()
[Link]("Inside super class A");
class B extends A
public void displayClass()
[Link]("Inside sub class B");
class C extends A
public void displayClass()
[Link]("Inside sub class C");
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 18
Advanced JAVA ****** 23CSP512
public class BoundedClass
public static void main(String a[])
// Creating object of sub class C and
// passing it to Bound as a type parameter.
Bound<C> bec = new Bound<C>(new C());
[Link]();
// Creating object of sub class B and
// passing it to Bound as a type parameter.
Bound<B> beb = new Bound<B>(new B());
[Link]();
// similarly passing super class A
Bound<A> bea = new Bound<A>(new A());
[Link]();
Output
Inside sub class C
Inside sub class B
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 19
Advanced JAVA ****** 23CSP512
Inside super class A
Now, we are restricted to only type A and its subclasses, So it will throw an error for any other type of
subclasses.
// This class only accepts type parameters as any class
// which extends class A or class A itself.
// Passing any other type will cause compiler time error
class Bound<T extends A>
private T objRef;
public Bound(T obj){
[Link] = obj;
public void doRunTest(){
[Link]();
class A
public void displayClass()
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 20
Advanced JAVA ****** 23CSP512
[Link]("Inside super class A");
class B extends A
public void displayClass()
[Link]("Inside sub class B");
class C extends A
public void displayClass()
[Link]("Inside sub class C");
public class BoundedClass
public static void main(String a[])
// Creating object of sub class C and
// passing it to Bound as a type parameter.
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 21
Advanced JAVA ****** 23CSP512
Bound<C> bec = new Bound<C>(new C());
[Link]();
// Creating object of sub class B and
// passing it to Bound as a type parameter.
Bound<B> beb = new Bound<B>(new B());
[Link]();
// similarly passing super class A
Bound<A> bea = new Bound<A>(new A());
[Link]();
Bound<String> bes = new Bound<String>(new String());
[Link]();
Output :
error: type argument String is not within bounds of type-variable T
Multiple Bounds
Bounded type parameters can be used with methods as well as classes and interfaces.
Java Generics supports multiple bounds also, i.e., In this case, A can be an interface or class. If A is
class, then B and C should be interfaces. We can’t have more than one class in multiple bounds.
Syntax:
<T extends superClassName & Interface>
class Bound<T extends A & B>
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 22
Advanced JAVA ****** 23CSP512
private T objRef;
public Bound(T obj){
[Link] = obj;
public void doRunTest(){
[Link]();
interface B
public void displayClass();
class A implements B
public void displayClass()
[Link]("Inside super class A");
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 23
Advanced JAVA ****** 23CSP512
public class BoundedClass
public static void main(String a[])
//Creating object of sub class A and
//passing it to Bound as a type parameter.
Bound<A> bea = new Bound<A>(new A());
[Link]();
Output
Inside super class A
Wildcards in Java
The question mark (?) is known as the wildcard in generic programming. It represents an unknown
type. The wildcard can be used in a variety of situations such as the type of a parameter, field, or local
variable; sometimes as a return type. Unlike arrays, different instantiations of a generic type are not
compatible with each other, not even explicitly. This incompatibility may be softened by the wildcard if ?
is used as an actual type parameter.
Types of wildcards in Java
1. Upper Bounded Wildcards:
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 24
Advanced JAVA ****** 23CSP512
These wildcards can be used when you want to relax the restrictions on a variable. For example, say you
want to write a method that works on List < Integer >, List < Double >, and List < Number >, you can do
this using an upper bounded wildcard.
To declare an upper-bounded wildcard, use the wildcard character ('?'), followed by the extends keyword,
followed by its upper bound.
public static void add(List<? extends Number> list)
Implementation:
// Java program to demonstrate Upper Bounded Wildcards
import [Link];
import [Link];
class WildcardDemo {
public static void main(String[] args)
// Upper Bounded Integer List
List<Integer> list1 = [Link](4, 5, 6, 7);
// printing the sum of elements in list
[Link]("Total sum is:" + sum(list1));
// Double list
List<Double> list2 = [Link](4.1, 5.1, 6.1);
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 25
Advanced JAVA ****** 23CSP512
// printing the sum of elements in list
[Link]("Total sum is:" + sum(list2));
private static double sum(List<? extends Number> list)
double sum = 0.0;
for (Number i : list) {
sum += [Link]();
return sum;
Output
Total sum is:22.0
Total sum is:15.299999999999999
Explanation:
In the above program, list1 and list2 are objects of the List class. list1 is a collection of Integer and list2 is
a collection of Double. Both of them are being passed to method sum which has a wildcard that extends
Number. This means that list being passed can be of any field or subclass of that field. Here, Integer and
Double are subclasses of class Number.
2. Lower Bounded Wildcards:
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 26
Advanced JAVA ****** 23CSP512
It is expressed using the wildcard character ('?'), followed by the super keyword, followed by its lower
bound: <? super A>.
Syntax: Collectiontype <? super A>
Implementation:
// Java program to demonstrate Lower Bounded Wildcards
import [Link];
import [Link];
class WildcardDemo {
public static void main(String[] args)
// Lower Bounded Integer List
List<Integer> list1 = [Link](4, 5, 6, 7);
// Integer list object is being passed
printOnlyIntegerClassorSuperClass(list1);
// Number list
List<Number> list2 = [Link](4, 5, 6, 7);
// Integer list object is being passed
printOnlyIntegerClassorSuperClass(list2);
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 27
Advanced JAVA ****** 23CSP512
public static void printOnlyIntegerClassorSuperClass(
List<? super Integer> list)
[Link](list);
Output
[4, 5, 6, 7]
[4, 5, 6, 7]
Explanation:
Here arguments can be Integer or superclass of Integer(which is Number). The method
printOnlyIntegerClassorSuperClass will only take Integer or its superclass objects. However, if we pass a
list of types Double then we will get a compilation error. It is because only the Integer field or its
superclass can be passed. Double is not the superclass of Integer.
Note: Use extend wildcard when you want to get values out of a structure and super wildcard when you
put values in a structure. Don’t use wildcard when you get and put values in a structure. You can specify
an upper bound for a wildcard, or you can specify a lower bound, but you cannot specify both.
3. Unbounded Wildcard:
This wildcard type is specified using the wildcard character (?), for example, List. This is called a list of
unknown types. These are useful in the following cases -
When writing a method that can be employed using functionality provided in Object class.
When the code is using methods in the generic class that doesn't depend on the type parameter
Implementation:
// Java program to demonstrate Unbounded wildcard
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 28
Advanced JAVA ****** 23CSP512
import [Link];
import [Link];
class unboundedwildcardemo {
public static void main(String[] args)
// Integer List
List<Integer> list1 = [Link](1, 2, 3);
// Double list
List<Double> list2 = [Link](1.1, 2.2, 3.3);
printlist(list1);
printlist(list2);
private static void printlist(List<?> list)
[Link](list);
Output
[1, 2, 3]
[1.1, 2.2, 3.3]
Generic Constructors and Interfaces in Java
Generics make a class, interface and, method, consider all (reference) types that are given dynamically as
parameters. This ensures type safety. Generic class parameters are specified in angle brackets “<>” after
the class name as of the instance variable.
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 29
Advanced JAVA ****** 23CSP512
Generic constructors are the same as generic methods. For generic constructors after the public keyword
and before the class name the type parameter must be placed. Constructors can be invoked with any type
of a parameter after defining a generic constructor. A constructor is a block of code that initializes the
newly created object. It is an instance method with no return type. The name of the constructor is same as
the class name. Constructors can be Generic, despite its class is not Generic.
Implementation:
Example:
// Java Program to illustrate Generic constructors
// Importing input output classes
import [Link].*;
// Class 1
// Generic class
class GenericConstructor {
// Member variable of this class
private double v;
// Constructor of this class where
// T is typename and t is object
<T extends Number> GenericConstructor(T t)
// Converting input number type to double
// using the doubleValue() method
v = [Link]();
// Method of this class
void show()
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 30
Advanced JAVA ****** 23CSP512
// Print statement whenever method is called
[Link]("v: " + v);
// Class 2 - Implementation class
// Main class
class GFG {
// Main driver method
public static void main(String[] args)
// Display message
[Link]("Number to Double Conversion:");
// Creating objects of type GenericConstructor i.e
// og above class and providing custom inputs to
// constructor as parameters
GenericConstructor obj1
= new GenericConstructor(10);
GenericConstructor obj2
= new GenericConstructor(136.8F);
// Calling method - show() on the objects
// using the dot operator
[Link]();
[Link]();
Output
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 31
Advanced JAVA ****** 23CSP512
Number to Double Conversion:
v: 10.0
v: 136.8000030517578
Output explanation: Here GenericConstructor() states a parameter of a generic type which is a subclass of
Number. GenericConstructor() can be called with any numeric type like Integer, Float, or Double. So, in
spite of GenericConstructor() is not a generic class, its constructor is generic.
Generic Interfaces in Java are the interfaces that deal with abstract data types. Interface help in the
independent manipulation of java collections from representation details. They are used to achieving
multiple inheritance in java forming hierarchies. They differ from the java class. These include all
abstract methods only, have static and final variables only. The only reference can be created to
interface, not objects, Unlike class, these don't contain any constructors, instance variables. This involves
the “implements” keyword. These are similar to generic classes.
The benefits of Generic Interface are as follows:
1. This is implemented for different data types.
2. It allows putting constraints i.e. bounds on data types for which interface is implemented.
Syntax:
interface interface-Name < type-parameter-list > {//....}
class class-name <type-parameter-list> implements interface-name <type-arguments-list> {//...}
Implementation: The following example creates an interface 'MinMax' which involves very basic
methods such as min(), max() just in order to illustrate as they return the minimum and maximum values
of given objects.
Example
// Java Program to illustrate Generic interfaces
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 32
Advanced JAVA ****** 23CSP512
// Importing java input output classes
import [Link].*;
// An interface that extends Comparable
interface MinMax<T extends Comparable<T> > {
// Declaring abstract methods
// Method with no body is abstract method
T min();
T max();
// Class 1 - Sub-class
// class extending Comparable and implementing interface
class MyClass<T extends Comparable<T> >
implements MinMax<T> {
// Member variable of 'MyClass' class
T[] values;
// Constructor of 'MyClass' class
MyClass(T[] obj) { values = obj; }
// Now, defining min() and max() methods
// for MimMax interface computation
// Defining abstract min() method
public T min()
// 'T' is typename and 'o1' is object_name
T o1 = values[0];
// Iterating via for loop over elements using
// length() method to get access of minimum element
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 33
Advanced JAVA ****** 23CSP512
for (int i = 1; i < [Link]; i++)
if (values[i].compareTo(o1) < 0)
o1 = values[i];
// Return the minimum element in an array
return o1;
// Defining abstract max() method
public T max()
// 'T' is typename and 'o1' is object_name
T o1 = values[0];
// Iterating via for loop over elements using
// length() method to get access of minimum element
for (int i = 1; i < [Link]; i++)
if (values[i].compareTo(o1) > 0)
o1 = values[i];
// Return the maximum element in an array
return o1;
// Class 2 - Main class
// Implementation class
class GFG {
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 34
Advanced JAVA ****** 23CSP512
// Main driver method
public static void main(String[] args)
// Custom entries in an array
Integer arr[] = { 3, 6, 2, 8, 6 };
// Create an object of type as that of above class
// by declaring Integer type objects, and
// passing above array to constructor
MyClass<Integer> obj1 = new MyClass<Integer>(arr);
// Calling min() and max() methods over object, and
// printing the minimum value from array elements
[Link]("Minimum value: " + [Link]());
// printing the maximum value from array elements
[Link]("Maximum value: " + [Link]());
Output
Minimum value: 2
Maximum value: 8
Output explanation: Here interface is declared with type parameter T, and its upper bound is Comparable
which is in [Link]. This states how objects are compared based on type of objects. Above T is declared
by MyClass and further passed to MinMax as MinMax needs a type that implements Comparable and
implementing class(MyClass) should have same bounds.
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 35
Advanced JAVA ****** 23CSP512
Note: Once a bound is established, it is not necessary to state it again in implements clause. If a class
implements generic interface, then class must be generic so that it takes a type parameter passed to
interface.
Generic Class Hierarchies in Java
Generic means parameterized types introduced in java5. These help in creating classes, interfaces,
methods, etc. A class or method which works on parameterized type known as "generic class " or "generic
method". Generics is a combination of language properties of the definition and use of Generic types and
methods. Collections were used before Generics which holds any type of objects i.e. non-generic. Using
Generics, it has become possible to create a single class, interface, or method that automatically works
with all types of data(Integer, String, Float, etc). It has expanded the ability to reuse the code safely and
easily. Generics also provide type safety (ensuring that an operation is being performed on the right type
of data before executing that operation).
Hierarchical classifications are allowed by Inheritance. Superclass is a class that is inherited. The subclass
is a class that does inherit. It inherits all members defined by super-class and adds its own, unique
elements. These uses extends as a keyword to do so.
Sometimes generic class acts like super-class or subclass. In Generic Hierarchy, All sub-classes move up
any of the parameter types that are essential by super-class of generic in the hierarchy. This is the same as
constructor parameters being moved up in a hierarchy.
Example 1: Generic super-class
// Java Program to illustrate generic class hierarchies
// Importing all input output classes
import [Link].*;
// Helper class 1
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 36
Advanced JAVA ****** 23CSP512
// Class 1 - Parent class
class Generic1<T> {
// Member variable of parent class
T obj;
// Constructor of parent class
Generic1(T o1) { obj = o1; }
// Member function of parent class
// that returns an object
T getobj1() { return obj; }
// Helper class 2
// Class 2 - Child class
class Generic2<T, V> extends Generic1<T> {
// Member variable of child class
V obj2;
Generic2(T o1, V o2)
// Calling super class using super keyword
super(o1);
obj2 = o2;
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 37
Advanced JAVA ****** 23CSP512
// Member function of child class
// that returns an object
V getobj2() { return obj2; }
// Class 3 - Main class
class GFG {
// Main driver method
public static void main(String[] args)
// Creating Generic2 (sub class) object
// Custom inputs as parameters
Generic2<String, Integer> x
= new Generic2<String, Integer>("value : ",
100);
// Calling method and printing
[Link](x.getobj1());
[Link](x.getobj2());
Output
value :
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 38
Advanced JAVA ****** 23CSP512
100
Note: A subclass can freely add its own type parameters, if necessary.
Example 2: Non-generic sub-class of generic sub-class
import [Link].*;
// non-generic super-class
class NonGen {
int n;
NonGen(int i) { n = i; }
int getval() { return n; }
// generic class sub-class
class Gen<T> extends NonGen {
T obj;
Gen(T o1, int i)
super(i);
obj = o1;
T getobj() { return obj; }
class GFG {
public static void main(String[] args)
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 39
Advanced JAVA ****** 23CSP512
Gen<String> w = new Gen<String>("Hello", 2021);
[Link]([Link]() + " " + [Link]());
Output
Hello 2021
Type Inference in Java:
Type inference in Java refers to the compiler’s ability to automatically deduce the type of a variable or the
return type of a method based on the context in which it is used, rather than requiring the developer to
explicitly specify the type. Type inference was enhanced in Java 7 and 8, and further improved in Java 10
with the introduction of the var keyword.
Key Features of Type Inference in Java:
1. Diamond Operator (Java 7): Before Java 7, when instantiating generic types, you had to specify the
generic type on both sides. The diamond operator <> was introduced in Java 7 to allow the compiler to
infer the generic type.
// Before Java 7
List<String> list = new ArrayList<String>();
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 40
Advanced JAVA ****** 23CSP512
// After Java 7 with the diamond operator
List<String> list = new ArrayList<>();
The compiler infers that ArrayList should hold String objects based on the declaration of list.
2. Type Inference in Method Calls (Java 8): Java 8 introduced lambda expressions and streams, where
type inference is used extensively. The compiler infers the types of parameters in lambda expressions
based on the context.
// Java infers the type of 'x' and 'y' based on the context
List<Integer> numbers = [Link](1, 2, 3, 4, 5);
[Link](x -> [Link](x));
In this example, the compiler infers that x is of type Integer because numbers is a list of integers.
3. var Keyword (Java 10): Java 10 introduced the var keyword, which allows you to declare local
variables without explicitly specifying their types. The compiler infers the type from the right-hand side of
the assignment.
var list = new ArrayList<String>();
// The compiler infers that 'list' is of type ArrayList<String>
var number = 10;
// The compiler infers that 'number' is of type int
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 41
Advanced JAVA ****** 23CSP512
While var allows more concise code, it can only be used for local variables, not for method parameters or
instance variables. The type must be determinable at compile time.
4. Type Inference in Generic Methods: Type inference also applies to generic methods. Java infers the
generic types based on the arguments passed to the method.
public static <T> T pick(T a, T b) {
return a != null ? a : b;
// Java infers that the method should return a String
String result = pick("Hello", "World");
When Type Inference Works:
In local variable declarations (with var).
In generic method calls.
In diamond operator usage with generics.
In lambda expressions where the parameter types can be inferred from the context.
When Type Inference Fails:
Ambiguous context: If the compiler cannot infer the type from the context.
var x; // Compilation error: Type cannot be inferred without an initializer.
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 42
Advanced JAVA ****** 23CSP512
Readability: Overuse of type inference, especially with var, can make code harder to read, as the type
information might not be immediately clear.
Example:
Here’s an example that combines several features of type inference in Java:
import [Link].*;
public class TypeInferenceExample {
public static void main(String[] args) {
// Using diamond operator
List<String> names = new ArrayList<>();
// Using var to declare a variable
var numbers = [Link](1, 2, 3, 4, 5);
// Lambda with type inference
[Link](n -> [Link](n));
// Type inference in a generic method
var result = pick("apple", "banana");
[Link]("Picked: " + result);
// Generic method with type inference
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 43
Advanced JAVA ****** 23CSP512
public static <T> T pick(T a, T b) {
return a != null ? a : b;
Key Points:
Type inference simplifies code, but the developer should be cautious about overusing it to avoid
reducing code clarity.
The diamond operator helps avoid repetitive type declarations.
var keyword reduces boilerplate, but should be used wisely where the inferred type is obvious.
Restrictions on Generics in Java
In Java, Generics are the parameterized types that allow us to create classes, interfaces, and methods in which the type of data
they are dealing with will be specified as a parameter. This ensures the type safety at the compilation time.
Syntax
class class_name<T>
//Body of the class
Here, the T is a type parameter that can be replaced with any valid identifier. Similarly, generic methods and interfaces are also
created.
Restrictions of Generics in Java
There are a few restrictions associated with the usage of generics that are mentioned below:
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 44
Advanced JAVA ****** 23CSP512
Type parameters cannot be instantiated
Restriction on using static members
Generic array Restrictions
primitive data types are not used with generic types
Generic Exception Restriction
1. Type parameters cannot be instantiated
It is not possible to create an instance of a type parameter. The compiler doesn't know what type of object
to create, their T is simply a placeholder. Below is the example code that shows the invalid creation of an
instance of T which leads to a compilation error.
Example:
// Java Program to demonstrate Generic class creation with
// the type parameter T.
class GenType<T> {
private T data;
GenType(T data)
// parameterized constructor
[Link] = data;
T getData() { return data; }
// main function
public static void main(String[] args)
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 45
Advanced JAVA ****** 23CSP512
GenType<Integer> gt = new GenType<>(10);
[Link]([Link]());
Output
10
2. Restriction on using static members
It is illegal for the static members(variables, methods) to use a type parameter declared by the enclosing
class. We will use the above example in this case to make the variable and method static, this also leads to
compile time error. Let's see in detail what the compiler says:
Example:
// Java Program to demonstrate Generic class creation with
// type parameter T.
class GenType<T> {
// illegal to make a variable as static.
// static T data; //compile-time Error:Cannot make a
// static reference to the non-static type T
T data;
GenType() {}
GenType(T data)
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 46
Advanced JAVA ****** 23CSP512
// parameterized constructor
[Link] = data;
T getData() { return data; }
public static void main(String[] args)
GenType<String> gt
= new GenType<>("Geek For Geeks!!");
[Link]([Link]());
Output
Geek For Geeks!!
3. Generic array Restrictions
There are two important generic restrictions that applied to arrays.
1. We cannot instantiate an array whose element type is a type parameter. There is no way for the
compiler to know what type of array to actually create. However, we can pass a reference to a type-
compatible array as a parameter and assign it to the object created. This is acceptable because the array
passed as a parameter has a known type, which will be of the same type as T at the time of object
creation.
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 47
Advanced JAVA ****** 23CSP512
2. We cannot create an array of type-specific generic references. The reason could be the same as in the
above case the compiler doesn't know what kind of array to create. This can be resolved by using a
wildcard, which is better than using a raw type because at least some type checking will be done.
Example:
// Java Program to implement
// Generic array Restrictions
import [Link];
public class GenArray<T extends Number> {
T obj;
T arr[];
GenArray(T o, T[] vals)
[Link] = o;
[Link]("value: " + obj);
// Invalid
// arr = new T[10];
// compile-time Error:Cannot
// create a generic array of T
// But, this is allowed because we are assigning the
// reference to the existing array.
arr = vals;
T[] getArray() { return arr; }
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 48
Advanced JAVA ****** 23CSP512
public static void main(String[] args)
Integer[] Array = { 1, 2, 3, 4, 5 };
GenArray<Integer> obj1
= new GenArray<Integer>(10, Array);
[Link](
[Link]([Link]()));
// illegal to create an array of type-specific
// generic references.
Output
value: 10
[1, 2, 3, 4, 5]
4. Primitive data types are not used with the generic types
We will get the compilation error if we use the primitive data types at the time of object creation. The
following code demonstrates the situation:
Example:
// Java Program to implement
// Primitive data types are not
// used with the generic types
import [Link].*;
// Driver Class
class Box<T> {
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 49
Advanced JAVA ****** 23CSP512
private T data;
Box(T data) { [Link] = data; }
T getData() { return data; }
public static void main(String[] args)
Box<Integer> b1 = new Box<Integer>(10);
// use of wrapper classes
Box<String> b2 = new Box<String>("Geek For Geeks");
[Link]("value: " + [Link]());
[Link]("value: " + [Link]());
Output
value: 10
value: Geek For Geeks
5. Generic Exception Restriction
We cannot create generic exception classes and cannot extend throwable (which is superior to all
exception classes in the exception class hierarchy). We will use the above example to understand this,
although we get an error if we execute this code, give it a try.
Example
// Java Program to implement
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 50
Advanced JAVA ****** 23CSP512
// Generic Exception Restriction
import [Link].*;
// generic class cannot extend throwable
class Box<T> extends Throwable {
private T data;
Box(T data) { [Link] = data; }
T getData() { return data; }
// main function
public static void main(String[] args)
Box<Integer> b1 = new Box<Integer>(10);
[Link]("value: " + [Link]());
Output:
Error: Could not find or load main class Box
Caused by: [Link]: Box
Mr. Dhananjaya M, Dept. of CSE, SJBIT Page 51