#
Generics in Java Example
#
Theory
This tutorial explains what is and how to use Generics in Java.
Java Generics was introduced to deal with type-safe objects.
Java Generics allows us to create a single class, interface, and method that can be used with different types of data (objects).
Please take a look at the following example and read carefully the comments. The code is self-explanatory.
This example is created from a simple Spring Boot application created with Spring Initializr. I am using Maven, Java 17, Spring Boot 3.1.0.
#
Example
From the base application downloaded from Spring Initializr, I updated the main class and added some classes as below:
package com.example.demo;
public class MyClass1 {
String str1;
public String getStr1() {
return str1;
}
public void setStr1(String str1) {
this.str1 = str1;
}
public MyClass1 (String str1) {
this.str1 = str1;
}
public int returnValue() {
return str1.length();
}
}
package com.example.demo;
public class MyClass2 {
int value1;
public int getValue1() {
return this.value1;
}
public void setValue1(int value1) {
this.value1 = value1;
}
public MyClass2(int value1) {
this.value1 = value1;
}
public int returnValue() {
return value1;
}
}
package com.example.demo;
// Generic Class : when instantiated, we use a generic class for the constructor
public class MyGenericClass <T> {
T myClass;
public MyGenericClass(T myClass1) {
this.myClass = myClass1;
}
public String objAddress() {
var valToReturn = this.myClass.toString();
return valToReturn;
}
// Generic methods : input/output variable types could be generic
public <U> void getVariableType(U var1) {
System.out.println( "We deal with a variable of "+var1.getClass().getName()+" type.");
}
}
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import java.util.concurrent.ExecutionException;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws InterruptedException, ExecutionException {
// Create the application context and start Spring Boot
ApplicationContext appContext = SpringApplication.run(DemoApplication.class, args);
System.out.println("DemoApplication - start");
MyClass1 myClass1 = new MyClass1("Hello");
MyClass2 myClass2 = new MyClass2(90);
MyGenericClass<MyClass1> intObj1 = new MyGenericClass(myClass1);
MyGenericClass<MyClass2> intObj2 = new MyGenericClass(myClass2);
System.out.println("Address for MyClass1 = "+intObj1.objAddress());
System.out.println("Address for MyClass2 = "+intObj2.objAddress());
intObj1.getVariableType(myClass2);
System.out.println("DemoApplication - end");
}
}
When the code run, we have the following output in the console:
DemoApplication - start
Address for MyClass1 = com.example.demo.MyClass1@73511076
Address for MyClass2 = com.example.demo.MyClass2@7927bd9f
We deal with a variable of com.example.demo.MyClass2 type.
DemoApplication - end
Process finished with exit code 0
Info
Generics in Java work only with reference type variables.
#
Bounds on Generics Classes
- we can limit the object types a generic class could work with
For doing this we can use the keyword "extends":
public class MyGenericClass <T extends Number> {
}
#
Bounds on Generics Methods
- we can limit the object types a generic method could work with as well. The generic types could be used as parameters or as response type.
For doing this we can use the keyword "extends":
public class MyGenericClass <T extends Number> {
public <U extend Number> void getVariableType(U var1) {
// Do something
}
}
- If the input or output object type are generics defined before we can also restrict the generic type we are using with the method.
public class MyGenericClass <T extends Number> {
public void getVariableType(MyGenericObject<? extends ClassA>) {
// Do something
}
}
Info
Instead "extends" (for "upper bound") we can use "super" (for "lower bound").