Creating a Custom Generic Class in Java
To indicate parameter types when creating generic classes, we utilize the <> symbol. The syntax used to generate objects of a generic class is as follows.
// To create an instance of a generic class
BaseType <T> obj = new BaseType <T>()
T isn't really a class. The usage of your class TemplateBuilder determines it at compile time. Consider it merely as a placeholder for a variety of potential kinds, one of which is "selected" based on your specific situation.
Take a look at the following example:
Imagine you want to create a class called Box that can store a certain type of item (the type of object to hold inside the box), but you want to reuse it in multiple contexts to hold different sorts of objects.
As a result, rather than fixing the actual type that the Box can accept, you define it as follows:
public class Box<T> {
private T t; // T stands for "Type"
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
When you use it, you subsequently take the following actions:
Box<Integer> integerBox = new Box<Integer>();
Why not make Box take an Object?
In actuality, this was only possible after Java 1.5. The Collections framework incorporated this in order to provide further type-safety in these circumstances.
The whole idea is that you couldn't force a specific instance of your Box to retain just Integers if it didn't have this method and instead used Object. On the other hand, if you restricted it to using only integers, you would have to design a different sort of Box class if you wanted to use it for items like strings or other types of objects.
Before Java 1.5, objects like ArrayList took plain Objects; however, there were often cases of type safety broken at runtime because the program is assuming a list of Integer objects, and by mistake, somewhere, a String is inserted. Generics (through this magic T) force types without restricting what they might be.
In your case, T extends TemplateBuilder is going one step further and stating that whatever T is, it must be a class that extends TemplateBuilder. If that weren't there, it would be any class that extends Object (the universal base class of Java).
Custom Generics
- Data structures always employ custom generics, such as when managing (storing/retrieving) lists of "things."
- Because custom generics embrace the polymorphism concepts, type checking is not necessary for the code to compile.
- However, a class can store a list of things without having any relationship with the "thing(s)" it is storing, in contrast to the "conventional" Object Oriented principles of polymorphism (The Fundamental Object Oriented Principle where A is a super class of B class is not required).
- You don't create distinct subclasses for each class of "things" you might want to store.
Consider the two unrelated classes listed below as an illustration. Despite being extremely simple, the following example illustrates the basic ideas behind custom generics:
/**
*
* Class A is a Custom Generic class that can be 'typed'
* to any kind of class using diamond 'T' syntax.
*
*/
class A<T>
{
// The instance variable of the object type 'T' known at run time
T theI;
// The constructor passing the object type 'T'
A(T anI)
{
this.theI = anI;
}
// Method to return the object 'T'
T getT()
{
return theI;
}
}
Below is the class B, which is unrelated to class A i.e., B does not extend A
/**
*
* Simple class which overrides the toString()
* method from Object's class toString() method
*
*/
class B
{
@Override
public String toString()
{
return "B Object";
}
public static void main(String[] args)
{
A<B> a = new A<>(new B());
System.out.println(a.getT());
}
}
In the Main method of class B above:
a.getT() returns the object 'T', which in this example is of type 'B' (This is an example of polymorphism).
a.getT() returns the object 'T', object instance C's method toString() gets IMPLICITLY called, as it is overriding Object's toString() method and prints "B Object".
The interesting aspect to note about Custom Generics and polymorphism is that:
In the context of custom generics, there are no constraints for a relationship among classes in order to execute polymorphism
e.g., Class B is unrelated to A above, i.e, and class B DOES not extend A.
In "traditional" object-orientated polymorphism principles, there is invariably a requirement constraint for classes to be related in some way. However, this is not required in custom generics.
Filename: B.java
/**
*
* Class A is a Custom Generic class that can be 'typed'
* to any kind of class using diamond 'T' syntax.
*
*/
/**
*
* Simple class which overrides the toString()
* method from Object's class toString() method
*
*/
class B
{
@Override
public String toString()
{
return "B Object";
}
public static void main(String[] args)
{
A<B> a = new A<>(new B());
System.out.println(a.getT());
}
}
class A<T>
{
// The instance variable of the object type 'T' known at run time
T theI;
// The constructor passing the object type 'T'
A(T anI)
{
this.theI = anI;
}
// Method to return the object 'T'
T getT()
{
return theI;
}
}
Output

publicinterface
TemplateBuilder
<T
extendsTemplateBuilder
>
The above means that the TemplateBuilder interface can be typedinto any class that extends TemplateBuilder.
Let's assume SomeClass extends TemplateBuilder then the following is fine:
TemplateBuilder<SomeClass> tbRef = ...
/* Using an Anonymous Inner Class reference to interface TemplateBuilder<SomeClass> */