0% found this document useful (0 votes)
6 views30 pages

Understanding Java Generics and Type Safety

The document explains the concept and purpose of Generics in Java, emphasizing type safety and the resolution of typecasting issues. It contrasts generic and non-generic collections, illustrating how generics ensure type safety and reduce the need for explicit typecasting. Additionally, it covers bounded types, wildcards, and generic methods, providing examples and syntax guidelines for their implementation.

Uploaded by

ADITYA PANDEY
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)
6 views30 pages

Understanding Java Generics and Type Safety

The document explains the concept and purpose of Generics in Java, emphasizing type safety and the resolution of typecasting issues. It contrasts generic and non-generic collections, illustrating how generics ensure type safety and reduce the need for explicit typecasting. Additionally, it covers bounded types, wildcards, and generic methods, providing examples and syntax guidelines for their implementation.

Uploaded by

ADITYA PANDEY
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

Generics

Date: 07-Oct-2025
=======================
Why we need Generics?
---------------------------
(Objective of Generics)
(Purpose of Generics)
-----------------------------------
=> The purpose of the Generics:
1) To provide the type safety
2) To resolve typecasting problems

Type safety:
---------------
import [Link];

public class GenericsDemo {


public static void main(String[] args) {
String[] data = new String[100]; // Array of strings
data[0] = "Ravi";
data[1] = "Ashok";
data[2] = "Sekhar";

// data[3] = new Integer(10); // compile-time error

ArrayList al = new ArrayList();


[Link]("Ravi");
[Link]("Ashok");
[Link]("Sekhar");

[Link](new Integer(10));
}
}

=> In the above example:


We have defined an array and an array list as objects.
=> Here the array has defined with strings
Into this, while inserting the data as string objects it is perfectly fine.
But while inserting an integer object to an array we can get "compile-time
error" as like below:

Exception in thread "main" [Link]: Unresolved compilation problem:


Type mismatch: cannot convert from Integer to String

=> So according to this, we can understand that array can give the guarantee
about the type safety.

=> Whereas while inserting string objects into array list is success and also
insertion with integer is also success.
Because the array list object never give any guarantee about "type safety".

=> Type safety means:


accessing and storing of the data objects with the specified type only.
When we can try to insert the data rather than the specified type we can get
compile-time error.
Typecasting problem:
-------------------------
import [Link];

public class GenericsDemo {


public static void main(String[] args) {
String[] data = new String[100]; // Array of strings
data[0] = "Ravi";
data[1] = "Ashok";
data[2] = "Sekhar";

// data[3] = new Integer(10);

ArrayList al = new ArrayList();


[Link]("Ravi");
[Link]("Ashok");
[Link]("Sekhar");

[Link](new Integer(10));

String d1 = data[0];
String d2 = data[1];
String d3 = data[2];

// String d4 = [Link](0); // CTE


String d4 = (String)[Link](0);
String d5 = (String)[Link](1);
}
}

=> Here in the above example,


while retrieving of data from arrays no requirement of explicit typecasting
because arrays can give the guarantee about type safety.
=> Whereas while retrieving of data from the array list we should perform the
typecasting explicitly because array list is not type safe object.

Why the collections are?


-----------------------------
=> Array is fixed in size
whereas collections are growable in size.

How to provide type safety and resolve typecasting problem from collections?
-------------------------------------------------------------------------------------
Using generics

import [Link];

public class GenericsDemo {


public static void main(String[] args) {
ArrayList al = new ArrayList();

[Link]("XYZ");
[Link](new Integer(10));
ArrayList<String> al1 = new ArrayList<String>();
[Link]("ABCD");
// [Link](new Integer(100)); CTE
}
}

=> The above program has defined with two objects al and al1
both are array list type
=> al is not type safe
but al1 is defined with generic
so, it can give the guarantee about the type safety.

import [Link];

public class GenericsDemo {


public static void main(String[] args) {
ArrayList al = new ArrayList();

[Link]("XYZ");
[Link](new Integer(10));

// String dt1 = [Link](0);

ArrayList<String> al1 = new ArrayList<String>();


[Link]("ABCD");
// [Link](new Integer(100)); CTE
[Link]("Ravi");

String d1 = [Link](0);
String d2 = [Link](1);
}
}

=> While retrieving of the data no requirement of typecasting explicitly


because al1 is defined with generic.

Difference between Generic object and non-generic object:


------------------------------------------------------------------
Non-Generic Object:
------------------------
1) ArrayList a = new ArrayList();
2) Not type safe object
3) typecasting is mandatory while retrieving of the data.

Generic Object:
-------------------
1) ArrayList<String> b = new ArrayList<String>();
2) Type safe objects.
3) Typecasting is not mandatory while retrieving of the data.

Q-1:
----
class ClassA{
data;
methods;
}

class ClassB extends ClassA{


data;
methods;
}

public class MainClass{


public static void main(String[] args){
ClassA ca = new ClassB();
}
}

Is the above program is correct/incorrect?

Ans: Correct
Because of the polymorphism, the parent class reference variable can use to
store the child class object creation.
===============================================
Collection (Parent)
List (Child)
ArrayList
LinkedList
Vector
Stack

Collection<String> c = new ArrayList<String>(); // correct


List<String> l = new ArrayList<String>(); // correct
here in the above statement:
List ==> base type
<String> ==> parameter type

=> Polymorphism is applicable to the base type only


but not to the parameter type.

ArrayList<Object> al = new ArrayList<String>(); // incorrect

=> In the above, we are defining polymorphism wrt the parameter type
so, this can lead to CTE.

Note:
-----
Generics were introduced in Java-1.5 version.
Date: 13-Oct-2025
------------------------------------------
Why Generics?
type safety
typecasting problem
Syntax for generics:
---------------------
ClassName/Base-Class<type-parameter/T> object-name = new Class-
Name<type/T>();
Example:
---------
ArrayList<String> al = new ArrayList<String>();
Q: Guess whether the below code/syntax is correct or incorrect?
---
ArrayList<int> x = new ArrayList<int>();

Ans: Incorrect
----
because that every collection is the group of objects but not with primitive
types.

Employee{
Name
Id
Designation
Mode-of-work
salary
}

Generic Classes
-------------------
Normal class: A class without any parameters
Example:
--------
class MainClass{
public static void main(String[] args){
[Link]("Hello");
}
}
=> Before java 1.5, the collections like array list can be defined as below:
Syntax: (non-generic form of array list)
class ArrayList{
add(Object o)
Object get(int index)
}
=> From java 1.5, the ArrayList can be defined as below:
Syntax: (generic form of array list)
class ArrayList<T>{
add(T t)
T get(int index)
}
=> A class with type parameter is called as "Generic class".

Custom Generic class/User-defined generic class:


--------------------------------------------------------
class Account<T>{
attributes
methods
}

Account<Gold> a1 = new Account<Gold>();


Account<Platinum> a2 = new Account<Platinum>();
Example for Custom Generic class:
----------------------------------------
class Gen<T>{
T obj;

Gen(T obj){
[Link] = obj;
}

public void show() {


[Link]("The type of obj =
"+[Link]().getName());
}

public T getObj() {
return obj;
}
}

public class CustomGenricClass {


public static void main(String[] args) {
Gen<String> g1 = new Gen<String>("Java");
[Link]();
[Link]([Link]());
Gen<Integer> g2 = new Gen<Integer>(1234);
[Link]();
[Link]([Link]());
}
}

Bounded Types
-------------------
Ex-1:
-----
class Test<T>{
public void m1(){
T a, b;
[Link](a+b);
[Link](a*b);
[Link](a/b);
}
}
public class Main{
public static void main(String[] args){
Test<Integer> t1 = new Test<Integer>();
Test<String> t2 = new Test<String>();
}
}

Here:
when a and b are Integer type of objects then the specified operations are
possible.
But when a and b are String type of objects then the above specified
operations are not possible.
Ex-2:
-----
class Test<T extends Number>{
public void m1(){
T a, b;
[Link](a+b);
[Link](a*b);
[Link](a/b);
}
}
public class Main{
public static void main(String[] args){
Test<Integer> t1 = new Test<Integer>();
Test<Float> t2 = new Test<Float>();
Test<Number> t3 = new Test<Number>();
}
}

Here:
T can be either:
Number type
or
Any sub class of Number type
=> Sub classes of Number class are:
Byte, Short, Integer, Long
Float and Double
Here:
The parameter 'T' was bounded with specific range
When the type parameter can be bounded to the specific range in the generic
class that parameter is called as "Bounded type parameter".
=> To bound the parameter with specific range, we must be use "extends"
keyword.

Bounded Type Vs Unbounded Type:


--------------------------------
class Test<T>{
// Unbounded Type
}

class Test<T extends Any-Class/Interface>{


Bounded Type
}

Q-1:
----
class Test<T extends Number>{
// logic
}
Test<Integer> t1 = new Test<Integer>(); // correct
Test<String> t2 = new Test<String>(); // Incorrect ==> Syntax Error
as below:
---------
Exception in thread "main" [Link]: Unresolved compilation problems:
Bound mismatch: The type String is not a valid substitute for the
bounded parameter <T extends Number> of the type Test<T>
Bound mismatch: The type String is not a valid substitute for the
bounded parameter <T extends Number> of the type Test<T>

at [Link]([Link])

Q-2: Is the below code correct?


----
class Test<T extends Runnable>{
// logic
}

Ans: It is correct
Generics in java is possible to define with classes and interfaces also.
When the type parameter is extended from a class
that type parameter can be either: defined class type or its sub class
type.
Similarly when the type parameter is extended from an interface
then:
that type parameter can be either:
defined interface type or its implemented classes type.

Ex:
Test<Runnable> t1 = new Test<Runnable>(); // correct
Test<Thread> t2 = new Test<Thread>(); // correct

here:
Thread is the implemented class of "Runnable" interface.
Q-3: is the below code correct?
----
class Test<T extends Number & Runnable>{
// logic
}

Ans: Correct
----
We do create the type parameter with combinations by using below syntax:

class Test<T extends ClassName & Interface>{


}
here:
T must be satisfy both:
ClassName and Interface

Q-4:
----
class Test<T extends Runnable & Number>{
}

Ans: Compile-time error


Because an interface must be define after the class name
Q-5: correct/incorrect?
----
class Test<T extends Number & Thread>{
}

Ans: Compile-time error

Here:
Internally:

Class T extends Number, Thread{


// NO
JAVA IS NOT ALLOW TO IMPLEMENT MULTIPLE INHERITANCE AT CLASS
LEVEL
}

class A{
}

class B{
}

class C extends A, B{
// Incorrect
}
Date: 14-Oct-2025
-------------------------------------------------
Note:
-----
Generic classes also called as "Template classes".

Conclusions of bounded types


----------------------------------
Q-1:
----
Find below which are correct and which are incorrect?
a) correct
class Test<T extends Number>{
// logic
}

b) incorrect
class Test<T implements Runnable>{
// logic
}

correct code:
-------------
class Test<T extends Runnable>

c) correct
class Test<T extends Runnable>{
// logic
}

d) incorrect
class Test<T super String>{
// logic
}

Note:
-----
Bounded types are always allow to define with only "extends" keyword
but not with other keywords like:
implements,
super etc.
We can replace the operation of implements with extends keyword while
defining bounded types.

Q-2:
----
Find below which are correct and which are incorrect?

a)
class Test<T>{
// logic
}

b) class Test<X>{
// logic
}

c) class Test<Ravi>{
// logic
}

Ans: All the above snippets are correct only

Note:
-----
The type parameter in the generic classes can be with any valid identifier.

Note:
-----
Based on the requirement, we can define/create generic classes with more
than one parameter.
But all the type parameters must be separate with comma.

Ex-1:
-----
class Test<X, Y>{
}

Ex-2:
-----
class Test<X, Y, Z>{
}
Ex-3:
-----
class HashMap<K, V>{
// here:
// K ==> key type
// V ==> value type
}

Wild-cart character (?):


----------------------------
Ex:
---
public static void m1(ArrayList<String> l){
// definition
}

public static void m1(ArrayList<Integer> l){


// definition
}

public static void m1(ArrayList<Double> l){


// definition
}

=> When we want to invoke the same method with different types parameters
then we must define the same method again and again based on the
parameter requirement.
=> With this approach code readability is decreased.
=> To overcome the above drawback we need to define that method with
"wild-cart character (?)".

Ex:
-----
public static void m1(ArrayList<?> l){
// definition
}

=> the above method can work with any type of parameter.

ArrayList<String> a1 = new ArrayList<String>();


ArrayList<Integer> a2 = new ArrayList<Integer>();
ArrayList<Double> a3 = new ArrayList<Double>();
m1(a1);
m1(a2);
m1(a3);

Conclusions with Wild-cart character(?):


---------------------------------------------
1) m1(ArrayList<?> l){
// [Link](10); CTE
// [Link](10.5); CTE
// [Link](null); correct
[Link](l);
}
=> The above definition can able to make execute the m1() method with array
list of any type.
That means we can call/invoke m1() method by passing ArrayList with any
type
But within the method we cannot perform any write operations on that passing
ArrayList object.
We can write with only "null".
That means, the above definition can be used for only read-operation.

2) m1(ArrayList<? extends X> l){


// here: X may be class or interface
// If 'X' is a class type then the '?' can be either 'X type' or 'its child
class'.
// If 'X' is an interface then the '?' can be either 'X' type or 'its
implemented classes'
}

Here:
while calling m1() with either 'interface type' or 'its implemented class'
within the method on that object we cannot perform any write operations
like:
[Link](10);
[Link](10.5);
The above statements can return "CTE".
But if we can write with 'null' is possible.
[Link](null); correct
=> This operation also useful for only read operations.

3) m1(ArrayList<? super String> l){


// here super is stating that
// ? can replace with:
// Either string type or its Super class (Object)
}
here:
When we can call m1():
Within the method we can perform write operations also based on the wild-
cart character behavior.

Generic Methods:
---------------------
=> also called as "Template methods".
=> The type parameter (T) with class is called as "Generic class".
Ex:
----
class Test<T>{
// implementation
// 'T' can be used within the class
// based on your requirement
T at1;
T at2;
void m1(T t){
}
T m2(){
}
}
=> The type parameter at method level is called as "Generic method".
Ex:
---
class Test{
public <T> void m1(T ob){
// T can be define within the method
based on your requirement
}
}

When the type parameter can be preceded to the return type of the method
such method is called as "generic method".

=> We can define bounded types at method level also.


Ex:
----
public <T extends X> m1(){
// So, here:
X ==> class or interface
}
Date: 15-Oct-2025
-------------------------------------------------
Q-1: Is the below code correct/incorrect?
----
class Test{
public static <T extends Runnable & Number> void m1(){
logic
}
}
Ans: Compile-time error
because:
here while defining the bounded types
the type parameter was extended from interface first rather than the class.

Q-2: Is the below code correct/incorrect?


----
class Test{
public static <T extends Number & Thread> void m1(){
logic
}
}

Ans: Compile-time error


because:
when we can define the bounded types with two classes combination
then internally JVM can treat that as multiple inheritance.
But in java multiple inheritance is not possible at class level.

Q-3:
----
class Test{
public static void m1(ArrayList x){
[Link](10);
[Link](10.5);
[Link](true);
}
public static void main(String[] args){
ArrayList<String> al = new ArrayList<String>(); // Generic
object
[Link]("java");
[Link]("Python");
// [Link](10); // CTE
m1(al);
[Link](al);
}
}

what is the output of the above code?

a) Compile-time error
b) ["java", "python", 10, 10.5, true]
c) ["java", "python"]
d) None of the above

Ans: b

While sending a generic object to the non-generic area


then:
the generic object can behave as same like non-generic object.

Generic Object Vs Non-Generic Object:


--------------------------------------
import [Link];
public class Conclusions {
public static void main(String[] args) {
ArrayList a1 = new ArrayList(); // Non-Generic Object
[Link](10);
[Link](10.5);
[Link](true);
[Link]("java");
ArrayList<String> a2 = new ArrayList<String>(); // Generic
object
[Link]("Core");
// [Link](10);
}

Note:
-----
The generic definition is only applicable at compile-time but not at run-time.

import [Link];

public class Conclusions {

public static void main(String[] args) {


ArrayList a = new ArrayList<String>(); // generic object
[Link](10);
[Link](10.5);
[Link]("java");
}
}

Here:
while assigning the generic object to the non-generic reference variable
and we have successfully added any type of objects.
because the definition of generic was at compiler only.
During the compilation, the compiler ca remove the generic definition from
object automatically as last step.

Q-4:
-----
ArrayList l1 = new ArrayList<String>();
[Link](10); [Link](10.5);
ArrayList l2 = new ArrayList<Integer>();
[Link](10); [Link](10.5);
ArrayList l3 = new ArrayList<Double>();
[Link](10); [Link](10.5);

are the above objects are equal or not?

Ans: all the above objects are equal.

Q-5:
-----
ArrayList<String> l = new ArrayList<String>();
ArrayList<String> l = new ArrayList();
are the above definitions same or different?

Ans: same behavior


here:
the both definitions are used to take only the string objects.

Q-6:
----
class Test{
public void m1(ArrayList<String> l){
logic
}

public void m1(ArrayList<Integer> l){


logic
}
}

is the above code correct/incorrect?

Ans: incorrect (CTE)

You might also like