Wir wissen nur: " Alle Instanzen einer Klasse haben dasselbe java.lang.Class-Objekt dieses Klassentyps. "
z.B)
Student a = new Student();
Student b = new Student();
Dann a.getClass() == b.getClass()
ist es wahr.
Nehmen wir nun an
Teacher t = new Teacher();
Ohne Generika ist das Folgende möglich.
Class studentClassRef = t.getClass();
Aber das ist jetzt falsch ..?
zB) public void printStudentClassInfo(Class studentClassRef) {}
kann mit aufgerufen werdenTeacher.class
Dies kann mit Generika vermieden werden.
Class<Student> studentClassRef = t.getClass(); //Compilation error.
Was ist nun T? T sind Typparameter (auch Typvariablen genannt); wird durch spitze Klammern (<>) begrenzt und folgt dem Klassennamen.
T ist nur ein Symbol, wie ein Variablenname (kann ein beliebiger Name sein), der beim Schreiben der Klassendatei deklariert wird. Später wird T
während der Initialisierung durch einen gültigen Klassennamen ersetzt ( HashMap<String> map = new HashMap<String>();
)
z.B) class name<T1, T2, ..., Tn>
Stellt also Class<T>
ein Klassenobjekt des spezifischen Klassentyps ' T
' dar.
Angenommen, Ihre Klassenmethoden müssen mit unbekannten Typparametern wie unten arbeiten
/**
* Generic version of the Car class.
* @param <T> the type of the value
*/
public class Car<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
Hier kann T als String
Typ als CarName verwendet werden
OR T kann als Integer
Typ als modelNumber verwendet werden.
OR T kann als Object
Typ als gültige Fahrzeuginstanz verwendet werden .
Hier ist das einfache POJO, das zur Laufzeit unterschiedlich verwendet werden kann.
Sammlungen, z. B.) List, Set, Hashmap, sind die besten Beispiele, die mit verschiedenen Objekten gemäß der Deklaration von T funktionieren. Wenn wir jedoch T als String deklariert haben,
z. B.) HashMap<String> map = new HashMap<String>();
werden nur Instanzobjekte der String-Klasse akzeptiert.
Generische Methoden
Generische Methoden sind Methoden, die ihre eigenen Typparameter einführen. Dies ähnelt der Deklaration eines generischen Typs, der Gültigkeitsbereich des Typparameters ist jedoch auf die Methode beschränkt, bei der er deklariert wird. Statische und nicht statische generische Methoden sowie generische Klassenkonstruktoren sind zulässig.
Die Syntax für eine generische Methode enthält einen Typparameter in spitzen Klammern und wird vor dem Rückgabetyp der Methode angezeigt. Bei generischen Methoden muss der Typparameterabschnitt vor dem Rückgabetyp der Methode angezeigt werden.
class Util {
// Generic static method
public static <K, V, Z, Y> boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
class Pair<K, V> {
private K key;
private V value;
}
Hier <K, V, Z, Y>
ist die Deklaration der Typen, die in den Methodenargumenten verwendet werden, die vor dem hier angegebenen Rückgabetyp stehen sollten boolean
.
Im Folgenden; Eine Typdeklaration <T>
ist auf Methodenebene nicht erforderlich, da sie bereits auf Klassenebene deklariert ist.
class MyClass<T> {
private T myMethod(T a){
return a;
}
}
Das Folgende ist jedoch falsch, da die Typparameter K, V, Z und Y auf Klassenebene nicht in einem statischen Kontext verwendet werden können (hier statische Methode).
class Util <K, V, Z, Y>{
// Generic static method
public static boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
ANDERE GÜLTIGE SZENARIEN SIND
class MyClass<T> {
//Type declaration <T> already done at class level
private T myMethod(T a){
return a;
}
//<T> is overriding the T declared at Class level;
//So There is no ClassCastException though a is not the type of T declared at MyClass<T>.
private <T> T myMethod1(Object a){
return (T) a;
}
//Runtime ClassCastException will be thrown if a is not the type T (MyClass<T>).
private T myMethod1(Object a){
return (T) a;
}
// No ClassCastException
// MyClass<String> obj= new MyClass<String>();
// obj.myMethod2(Integer.valueOf("1"));
// Since type T is redefined at this method level.
private <T> T myMethod2(T a){
return a;
}
// No ClassCastException for the below
// MyClass<String> o= new MyClass<String>();
// o.myMethod3(Integer.valueOf("1").getClass())
// Since <T> is undefined within this method;
// And MyClass<T> don't have impact here
private <T> T myMethod3(Class a){
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<T> a :: a is Class object of type T
//<T> is overriding of class level type declaration;
private <T> Class<T> myMethod4(Class<T> a){
return a;
}
}
Und schließlich muss die statische Methode immer explizit <T>
deklariert werden. Es wird nicht von der Klassenstufe abgeleitet Class<T>
. Dies liegt daran, dass die Klassenstufe T an die Instanz gebunden ist.
Lesen Sie auch Einschränkungen für Generika
Platzhalter und Subtypisierung
Typargument für eine generische Methode