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
Aus der Java-Dokumentation:
[...] Überraschenderweise wurde die Klassenklasse generiert. Klassenliterale fungieren jetzt als Typ-Token und bieten Informationen zur Laufzeit und zur Kompilierungszeit. Dies ermöglicht einen Stil statischer Fabriken, der durch die Methode getAnnotation in der neuen AnnotatedElement-Schnittstelle veranschaulicht wird:
Dies ist eine generische Methode. Es leitet den Wert seines Typparameters T aus seinem Argument ab und gibt eine geeignete Instanz von T zurück, wie im folgenden Snippet dargestellt:
Vor Generika hätten Sie das Ergebnis an Author übertragen müssen. Außerdem hätten Sie den Compiler nicht überprüfen lassen können, ob der tatsächliche Parameter eine Unterklasse von Annotation darstellt. [...]
Nun, ich musste so etwas nie benutzen. Jemand?
quelle
Class<? extends X>
Notation, die ich dachte, könnte ich sie nur auf "Dienst" -Typen beschränken. Außer es gab keinen gemeinsamen "Service" -Typ, also konnte ich es nur mit tunClass<?>
. Ach.Ich habe es
class<T>
nützlich gefunden , wenn ich Service Registry Lookups erstelle. Z.Bquelle
Wie andere Antworten zeigen, gibt es viele und gute Gründe, warum dies
class
generisch gemacht wurde. Es gibt jedoch viele Fälle, in denen Sie nicht wissen, mit welchem generischen Typ Sie arbeiten sollenClass<T>
. In diesen Fällen können Sie die gelben Eclipse-Warnungen einfach ignorieren oder verwendenClass<?>
... So mache ich das;)quelle
@SuppressWarnings("unchecked")
kommt zur Rettung! (Nur vorsichtig sein , immer es wie möglich so klein einen Umfang anzuwenden , wie es tut obskure mögliche Probleme in Ihrem Code.)Nach der Antwort von @Kire Haglin finden Sie ein weiteres Beispiel für generische Methoden in der Dokumentation zum JAXB-Unmarshalling :
Auf diese Weise können Sie
unmarshal
ein Dokument eines beliebigen JAXB-Inhaltsbaumtyps zurückgeben.quelle
Sie möchten häufig Platzhalter mit verwenden
Class
. Mit können Sie beispielsweiseClass<? extends JComponent>
angeben, dass die Klasse eine Unterklasse von istJComponent
. Wenn Sie dieClass
Instanz von abgerufen habenClass.forName
, könnenClass.asSubclass
Sie die Umwandlung verwenden, bevor Sie beispielsweise versuchen, eine Instanz zu erstellen.quelle
In Java
<T>
bedeutet generische Klasse. Eine generische Klasse ist eine Klasse, die mit jedem Datentyp arbeiten kann, oder mit anderen Worten, wir können sagen, dass sie vom Datentyp unabhängig ist.Wobei T Typ bedeutet. Wenn Sie nun eine Instanz dieser Shape-Klasse erstellen, müssen Sie dem Compiler mitteilen, für welchen Datentyp dies arbeiten wird.
Beispiel:
Ganzzahl ist ein Typ und String ist auch ein Typ.
<T>
steht speziell für generischen Typ. Gemäß Java Docs - Ein generischer Typ ist eine generische Klasse oder Schnittstelle, die über Typen parametrisiert wird .quelle
Um nur ein weiteres Beispiel zu nennen: Mit der generischen Version von Class (
Class<T>
) können generische Funktionen wie die folgende geschrieben werden.quelle
Am Anfang ist es verwirrend. Aber es hilft in den folgenden Situationen:
quelle
Action a = new Action()
?Action
In einer SchnittstelleSomeAction
versuchen wir, eine Instanz von zu bekommen. Wir haben nur den NamenSomeAction
zur Laufzeit zur Verfügung.Verwenden Sie einfach die Rindfleischklasse:
quelle