Generics enable classes, interfaces, and methods to take other classes and interfaces as type parameters.
This example uses generic class Param
to take a single type parameter T
, delimited by angle brackets (<>
):
public class Param<T> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
To instantiate this class, provide a type argument in place of T
. For example, Integer
:
Param<Integer> integerParam = new Param<Integer>();
The type argument can be any reference type, including arrays and other generic types:
Param<String[]> stringArrayParam;
Param<int[][]> int2dArrayParam;
Param<Param<Object>> objectNestedParam;
In Java SE 7 and later, the type argument can be replaced with an empty set of type arguments (<>
) called the diamond:
Param<Integer> integerParam = new Param<>();
Unlike other identifiers, type parameters have no naming constraints. However their names are commonly the first letter of their purpose in upper case. (This is true even throughout the official JavaDocs.)
Examples include T
for "type", E
for "element" and K
/V
for "key"/"value".
public abstract class AbstractParam<T> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
AbstractParam
is an abstract class declared with a type parameter of T
. When extending this class, that type parameter can be replaced by a type argument written inside <>
, or the type parameter can remain unchanged. In the first and second examples below, String
and Integer
replace the type parameter. In the third example, the type parameter remains unchanged. The fourth example doesn't use generics at all, so it's similar to if the class had an Object
parameter. The compiler will warn about AbstractParam
being a raw type, but it will compile the ObjectParam
class. The fifth example has 2 type parameters (see "multiple type parameters" below), choosing the second parameter as the type parameter passed to the superclass.
public class Email extends AbstractParam<String> {
// ...
}
public class Age extends AbstractParam<Integer> {
// ...
}
public class Height<T> extends AbstractParam<T> {
// ...
}
public class ObjectParam extends AbstractParam {
// ...
}
public class MultiParam<T, E> extends AbstractParam<E> {
// ...
}
The following is the usage:
Email email = new Email();
email.setValue("[email protected]");
String retrievedEmail = email.getValue();
Age age = new Age();
age.setValue(25);
Integer retrievedAge = age.getValue();
int autounboxedAge = age.getValue();
Height<Integer> heightInInt = new Height<>();
heightInInt.setValue(125);
Height<Float> heightInFloat = new Height<>();
heightInFloat.setValue(120.3f);
MultiParam<String, Double> multiParam = new MultiParam<>();
multiParam.setValue(3.3);
Notice that in the Email
class, the T getValue()
method acts as if it had a signature of String getValue()
, and the void setValue(T)
method acts as if it was declared void setValue(String)
.
It is also possible to instantiate with anonymous inner class with an empty curly braces ({}
):
AbstractParam<Double> height = new AbstractParam<Double>(){};
height.setValue(198.6);
Note that using the diamond with anonymous inner classes is not allowed.
Java provides the ability to use more than one type parameter in a generic class or interface. Multiple type parameters can be used in a class or interface by placing a comma-separated list of types between the angle brackets. Example:
public class MultiGenericParam<T, S> {
private T firstParam;
private S secondParam;
public MultiGenericParam(T firstParam, S secondParam) {
this.firstParam = firstParam;
this.secondParam = secondParam;
}
public T getFirstParam() {
return firstParam;
}
public void setFirstParam(T firstParam) {
this.firstParam = firstParam;
}
public S getSecondParam() {
return secondParam;
}
public void setSecondParam(S secondParam) {
this.secondParam = secondParam;
}
}
The usage can be done as below:
MultiGenericParam<String, String> aParam = new MultiGenericParam<String, String>("value1", "value2");
MultiGenericParam<Integer, Double> dayOfWeekDegrees = new MultiGenericParam<Integer, Double>(1, 2.6);