All we know is “All instances of a any class shares the same java.lang.Class object of that type of class”
e.g)
Student a = new Student();
Student b = new Student();
Then a.getClass() == b.getClass() is true.
Now assume
Teacher t = new Teacher();
without generics the below is possible.
Class studentClassRef = t.getClass();
But this is wrong now ..?
e.g) public void printStudentClassInfo(Class studentClassRef) {} can be called with Teacher.class
This can be avoided using generics.
Class
Now what is T ?? T is type parameters (also called type variables); delimited by angle brackets (<>), follows the class name.
T is just a symbol, like a variable name (can be any name) declared during writing of the class file. Later that T will be substituted with valid Class name during initialization (HashMap
e.g) class name
So Class
Assume that your class methods has to work with unknown type parameters like below
/**
* Generic version of the Car class.
* @param
*/
public class Car
// T stands for “Type”
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
Here T can be used as String type as CarName
OR T can be used as Integer type as modelNumber,
OR T can be used as Object type as valid car instance.
Now here the above is the simple POJO which can be used differently at runtime.
Collections e.g) List, Set, Hashmap are best examples which will work with different objects as per the declaration of T, but once we declared T as String
e.g) HashMap
Generic Methods
Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter’s scope is limited to the method where it is declared. Static and non-static generic methods are allowed, as well as generic class constructors.
The syntax for a generic method includes a type parameter, inside angle brackets, and appears before the method’s return type. For generic methods, the type parameter section must appear before the method’s return type.
class Util {
// Generic static method
public static
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
class Pair
private K key;
private V value;
}
Here
In the below; type declaration
class MyClass
private T myMethod(T a){
return a;
}
}
But below is wrong as class-level type parameters K, V, Z, and Y cannot be used in a static context (static method here).
class Util
// Generic static method
public static boolean compare(Pair
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
OTHER VALID SCENARIOS ARE
class MyClass
//Type declaration
private T myMethod(T a){
return a;
}
//
//So There is no ClassCastException though a is not the type of T declared at MyClass
private
return (T) a;
}
//Runtime ClassCastException will be thrown if a is not the type T (MyClass
private T myMethod1(Object a){
return (T) a;
}
// No ClassCastException
// MyClass
// obj.myMethod2(Integer.valueOf(“1”));
// Since type T is redefined at this method level.
private
return a;
}
// No ClassCastException for the below
// MyClass
// o.myMethod3(Integer.valueOf(“1”).getClass())
// Since
// And MyClass
private
return (T) a;
}
// ClassCastException for o.myMethod3(Integer.valueOf(“1”).getClass())
// Should be o.myMethod3(String.valueOf(“1”).getClass())
private T myMethod3(Class a){
return (T) a;
}
// Class
//
private
return a;
}
}
And finally Static method always needs explicit
Also read Restrictions on Generics
Wildcards and Subtyping
type argument for a generic method
Using the generified version of class Class allows you, among other things, to write things like
Class extends Collection> someCollectionClass = someMethod();
and then you can be sure that the Class object you receive extends Collection, and an instance of this class will be (at least) a Collection.