Java Language Creazione di una classe generica


Esempio

Generics abilita classi, interfacce e metodi per prendere altre classi e interfacce come parametri di tipo.

Questo esempio utilizza la classe generica Param per prendere un singolo parametro di tipo T , delimitato da parentesi angolari ( <> ):

public class Param<T> {
    private T value;

    public T getValue() {
        return value;
    }

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

Per creare un'istanza di questa classe, fornire un argomento di tipo al posto di T Ad esempio, Integer :

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

L'argomento type può essere qualsiasi tipo di riferimento, inclusi gli array e altri tipi generici:

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

In Java SE 7 e versioni successive, l'argomento type può essere sostituito con un set vuoto di argomenti type ( <> ) chiamato diamond :

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

A differenza di altri identificatori, i parametri di tipo non hanno vincoli di denominazione. Tuttavia i loro nomi sono comunemente la prima lettera del loro scopo in maiuscolo. (Questo è vero anche in tutti i JavaDocs ufficiali.)
Gli esempi includono T per "tipo" , E per "elemento" e K / V per "chiave" / "valore" .


Estendere una classe generica

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

    public T getValue() {
        return value;
    }

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

AbstractParam è una classe astratta dichiarata con un parametro di tipo T Quando si estende questa classe, quel parametro di tipo può essere sostituito da un argomento di tipo scritto all'interno di <> , oppure il parametro type può rimanere invariato. Nel primo e nel secondo esempio di seguito, String e Integer sostituiscono il parametro type. Nel terzo esempio, il parametro type rimane invariato. Il quarto esempio non usa affatto i generici, quindi è simile a se la classe avesse un parametro Object . Il compilatore avverte che AbstractParam è un tipo non ObjectParam , ma compilerà la classe ObjectParam . Il quinto esempio ha 2 parametri di tipo (vedi "parametri di tipo multiplo" sotto), scegliendo il secondo parametro come parametro di tipo passato alla superclasse.

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

Quanto segue è l'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);

Si noti che nella classe Email , il metodo T getValue() agisce come se avesse una firma di String getValue() , e il void setValue(T) agisce come se fosse stato dichiarato void setValue(String) .

È anche possibile creare un'istanza con classe interna anonima con parentesi graffe vuote ( {} ):

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

Nota che l' uso del diamante con classi interne anonime non è permesso.


Parametri di tipo multiplo

Java offre la possibilità di utilizzare più di un parametro di tipo in una classe o interfaccia generica. È possibile utilizzare più parametri di tipo in una classe o in un'interfaccia inserendo un elenco di tipi separati da virgole tra parentesi angolari. Esempio:

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

L'utilizzo può essere eseguito come di seguito:

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