0% found this document useful (0 votes)
17 views51 pages

Understanding Java Generics Explained

The document provides an overview of Generics in Java, explaining their purpose, advantages, and limitations. It covers the implementation of generic methods and classes, type safety, and the importance of using reference types instead of primitives. Additionally, it highlights the benefits of code reusability and type safety while also discussing the complexities and performance overhead associated with generics.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views51 pages

Understanding Java Generics Explained

The document provides an overview of Generics in Java, explaining their purpose, advantages, and limitations. It covers the implementation of generic methods and classes, type safety, and the importance of using reference types instead of primitives. Additionally, it highlights the benefits of code reusability and type safety while also discussing the complexities and performance overhead associated with generics.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

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

Common questions

Powered by AI

Bounded type parameters in Java generics enhance flexibility by allowing methods or classes to operate on a subset of types that have a certain superclass or implement a certain interface. This ensures that the operations can only be performed on objects that fulfill specific constraints, improving the robustness and type safety of the program. The flexibility allows implementations of algorithms that are applicable across various subtypes while retaining type safety by preventing incompatible types from being used inadvertently .

Generics in Java improve type safety by ensuring that errors related to incompatible types are caught at compile time, rather than at runtime. This is achieved by using type parameters that allow classes, interfaces, and methods to operate on specified types of data while preventing runtime type casting errors. By introducing type parameters, generics enforce a strict type-checking mechanism and prevent operations on incompatible types, thus enhancing code safety and reliability .

Java generics cannot directly work with primitive data types because generics rely on objects, and primitives like int, char, and double are not objects but raw values. This limitation is addressed by using wrapper classes such as Integer, Character, and Double, which encapsulate the primitive values into objects that generics can handle. This approach allows the benefits of generics to be applied to primitive data types, albeit with the overhead of object creation .

Type erasure in Java generics refers to the process by which the compiler removes all the generic type information during the compilation phase. This means the coded generic type parameters are replaced with their bounds or Object during runtime. While type erasure ensures backward compatibility with non-generic legacy code, it leads to limitations in runtime type identification. Since type information is erased, methods relying on reflection cannot access generic type parameters, potentially leading to errors if not properly managed. Additionally, type erasure can cause performance overhead as generic types are converted to Object .

Java generics have several notable limitations. First, they work only with reference types; primitive types require the use of corresponding wrapper classes such as Integer or Double. Second, generics suffer from type erasure—which means that all the type information is removed at runtime, potentially leading to issues with reflection and type safety. Additionally, static members of a generic class cannot refer to generic type parameters since they belong to the class, not to any specific instance. Another limitation is that arrays of generic types cannot be instantiated, making some operations on arrays cumbersome .

Yes, a Java generic class can implement multiple interfaces. When using generics, the type parameter can be constrained to multiple interfaces by using the '&' symbol in the type declaration. For example, '<T extends InterfaceA & InterfaceB>' allows a generic class to ensure that the type parameter T implements both InterfaceA and InterfaceB. This approach provides enhanced flexibility and ensures that objects of T exhibit behaviors specified by multiple interfaces, fostering code reuse and interface-driven design .

Generic methods in Java are defined with a type parameter that is independent of any class-wide type parameters, allowing these methods to work with different types irrespective of the class. This makes them more flexible, as they can be used alongside non-generic classes. In contrast, generic classes define a type parameter that applies to the entire class and is consistent across all the methods within that class. This means an instance of a generic class is bound to a particular type, as defined at its creation. Generic methods focus on method-specific type safety and flexibility, whereas generic classes provide type-specific encapsulation for all its contents .

Java generics enhance the readability and maintainability of code by allowing developers to specify consistent data types, which makes the code easier to understand and navigate. By clearly defining the type parameters, generics reduce the need for explicit type casting, which can often clutter code and introduce potential run-time errors. This clarity in type usage makes it simpler to comprehend the flow of data through various parts of the program, thus facilitating easier debugging and code modification .

Java wildcards are represented by the '?' symbol and are used in generic programming to denote an unknown type, hence adding flexibility when defining method arguments. Wildcards allow methods to accept parameters of various types without having to specify each type explicitly. There are three types of wildcards: unbounded, upper-bounded, and lower-bounded. Unbounded wildcards can take any type, upper-bounded wildcards restrict parameters to a specific type or its subclasses, and lower-bounded wildcards allow a type along with its parents. This flexibility enables methods to handle a broader range of data structures effectively, promoting code reuse and generality .

Generic constructors in Java allow constructor logic to be independent of specific data types, which is not possible with non-generic constructors. In a generic constructor, the type parameter is specified before the constructor name and can be utilized to accept parameters of various types, enhancing the constructor's versatility. This feature ensures type safety by allowing conversion and manipulation of data within the constructor according to the generic type, providing flexibility and reducing type-based errors during object instantiation .

You might also like