Java Language Creando una clase genérica


Ejemplo

Los genéricos permiten que las clases, interfaces y métodos tomen otras clases e interfaces como parámetros de tipo.

Este ejemplo utiliza la clase genérica Param para tomar un solo tipo de parámetro T , delimitado por corchetes angulares ( <> ):

public class Param<T> {
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}

Para crear una instancia de esta clase, proporcione un argumento de tipo en lugar de T Por ejemplo, Integer :

Param<Integer> integerParam = new Param<Integer>();

El argumento de tipo puede ser cualquier tipo de referencia, incluidas las matrices y otros tipos genéricos:

Param<String[]> stringArrayParam;
Param<int[][]> int2dArrayParam;
Param<Param<Object>> objectNestedParam;

En Java SE 7 y versiones posteriores, el argumento de tipo se puede reemplazar con un conjunto vacío de argumentos de tipo ( <> ) llamado diamante :

Java SE 7
Param<Integer> integerParam = new Param<>();

A diferencia de otros identificadores, los parámetros de tipo no tienen restricciones de denominación. Sin embargo, sus nombres suelen ser la primera letra de su propósito en mayúsculas. (Esto es cierto incluso en los JavaDocs oficiales).
Los ejemplos incluyen T para "tipo" , E para "elemento" y K / V para "clave" / "valor" .


Extendiendo una clase genérica

public abstract class AbstractParam<T> {
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}

AbstractParam es una clase abstracta declarada con un parámetro de tipo de T Al extender esta clase, ese parámetro de tipo puede reemplazarse por un argumento de tipo escrito dentro de <> , o el parámetro de tipo puede permanecer sin cambios. En el primer y segundo ejemplo a continuación, String y Integer reemplazan el parámetro de tipo. En el tercer ejemplo, el parámetro de tipo permanece sin cambios. El cuarto ejemplo no usa genéricos en absoluto, por lo que es similar a si la clase tuviera un parámetro Object . El compilador advertirá que AbstractParam es un tipo sin ObjectParam , pero compilará la clase ObjectParam . El quinto ejemplo tiene 2 parámetros de tipo (consulte "parámetros de tipo múltiple" a continuación), seleccionando el segundo parámetro como el parámetro de tipo pasado a la superclase.

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> {
    // ...
}

El siguiente es el uso:

Email email = new Email();
email.setValue("test@example.com");
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);

Observe que en la clase de Email , el método T getValue() actúa como si tuviera una firma de String getValue() , y el método void setValue(T) actúa como si fuera declarado void setValue(String) .

También es posible crear una instancia con una clase interna anónima con llaves vacías ( {} ):

AbstractParam<Double> height = new AbstractParam<Double>(){};
height.setValue(198.6);

Tenga en cuenta que no se permite usar el diamante con clases internas anónimas.


Parámetros de tipo múltiple

Java ofrece la posibilidad de utilizar más de un parámetro de tipo en una clase o interfaz genérica. Se pueden usar múltiples parámetros de tipo en una clase o interfaz colocando una lista de tipos separados por comas entre los corchetes angulares. Ejemplo:

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;
    }
}

El uso se puede hacer de la siguiente manera:

MultiGenericParam<String, String> aParam = new MultiGenericParam<String, String>("value1", "value2");
MultiGenericParam<Integer, Double> dayOfWeekDegrees = new MultiGenericParam<Integer, Double>(1, 2.6);