Ich denke verwenden, dass, um das zu verstehen, muss man zuerst die feinen Unterschiede zwischen Typen und Klassen verstehen: Objekte haben Klassen, haben Referenzen Typen.
Klassen vs Typen
denke ich, ein Beispiel ist ein guter Weg zu erklären, was ich hier meine. Lassen Sie die Existenz der folgenden Klassenhierarchie übernehmen:
class Mammal {}
class Feline extends Mammal {}
class Lion extends Feline {}
class Tiger extends Feline {}
Dank Polymorphismus Subtyp wir mehrere Verweise auf das gleiche Objekt erklären könnte.
Tiger tiger = new Tiger(); //!
Feline feline = tiger;
Mammal mammal = feline;
Interessanterweise, wenn wir jeder dieser Referenzen gebeten, den Namen ihrer Klasse, die sie alle würden mit der gleichen Antwort antworten: „Tiger“.
System.out.println(tiger.getClass().getName()); //yields Tiger
System.out.println(feline.getClass().getName()); //yields Tiger
System.out.println(mammal.getClass().getName()); //yield Tiger
Das bedeutet die tatsächliche Klasse des Objekts festgelegt ist, ist seine Klasse diejenige, die wir verwenden, um es zu instanziieren, wenn wir die „neuen“ Betreiber in unserem obigen Code verwendet.
Die Referenzen, auf der anderen Seite können verschiedene Typen, polymorph mit der tatsächlichen Klasse von Objekt kompatibel (d. H. Ein Tiger in diesem Fall).
So haben Objekte eine feste Klasse, während Referenzen kompatible Typen haben.
Dies ist eher verwirrend, da die Klassennamen die gleichen sind, die wir verwenden, um die Typen unserer Referenzen zu benennen, aber semantisch gesehen gibt es einen feinen Unterschied, wie wir oben sehen können.
Der vielleicht verwirrendste Teil ist die Erkenntnis, dass Klassen auch Objekte sind, und daher können sie kompatible Referenzen von ihren eigenen haben. Zum Beispiel:
Class<Tiger> tigerClass = null;
Class<? extends Tiger> someTiger = tigerClass;
Class<? extends Feline> someFeline = tigerClass;
Class<? extends Mammal> someMammal = tigerClass;
In meinem Code über das Objekt verwiesen wird, ist ein Klassenobjekt (was ich für vorerst null links), und diese Referenzen hier haben verschiedene Arten verwendet werden, dass die hypothetische Objekt zu erreichen.
Also, das Wort "Klasse" wird hier verwendet, um einen "Referenztyp" zu nennen, der auf ein tatsächliches Klassenobjekt verweist, dessen Typ mit einer dieser Referenzen kompatibel ist.
In meinem obigen Beispiel konnte ich ein solches Klassenobjekt nicht definieren, da ich die ursprüngliche Variable auf null initialisiert habe. Dies ist beabsichtigt, und in einem Moment werden wir sehen, warum.
Über getClass
und getSubclass
auf Referenzen aufrufen
Nach @ Jatin das Beispiel, das die getClass
Methode betrachtet, jetzt wollen wir das folgende Stück von polymorphen Code betrachten:
Mammal animal = new Tiger();
Jetzt wissen wir, dass unabhängig der Tatsache, dass unsere animal
Referenz vom Typ Mammal
ist, ist die tatsächliche Klasse des Objekts, und wird immer Tiger
(dh Klasse) sein.
Was sollen wir bekommen, wenn wir das tun?
? type = mammal.getClass()
Sollte type
ein Class<Mammal>
oder ein Class<Tiger>
sein?
Nun, das Problem ist, dass, wenn der Compiler sieht eine Referenz vom Typ Mammal
, und es kann nicht sagen, was die tatsächliche Klasse des Objekts ist dieser Verweis auf zeigt. Das konnte nur zur Laufzeit festgestellt werden, oder? Es kann tatsächlich ein Säugetier sein, aber es kann auch eine seiner Unterklassen sein, wie ein Tiger, oder?
Also, wenn wir nach seiner Klasse fragen, bekommen wir Class<Mammal>
nicht, weil der Compiler nicht sicher sein kann. Stattdessen erhalten wir eine Class<? extends Mammal>
, und das macht viel mehr Sinn, denn schließlich weiß der Compiler, dass basierend auf den Regeln des Subtyp-Polymorphismus die gegebene Referenz auf einen Mammal oder einen seiner Subtypen zeigen kann.
An dieser Stelle können Sie wahrscheinlich die feinen Nuancen der Verwendung des Wortes class hier sehen. Es scheint, dass das, was wir tatsächlich aus der getClass()
-Methode bekommen, irgendeine Art von Referenz ist, die wir verwenden, um auf die tatsächliche Klasse des ursprünglichen Objekts zu zeigen, wie wir bereits zuvor erläutert hatten.
Nun, das gleiche könnte über die asSubclass
Methode gesagt werden. Zum Beispiel:
Mammal tiger = new Tiger();
Class<? extends Mammal> tigerAsMammal = tiger.getClass();
Class<? extends Feline> tigerAsFeline = tigerAsMammal.asSubclass(Feline.class);
Wenn wir rufen asSubclass
wir ein Hinweis auf die tatsächliche Art der Klasse werden immer durch unsere Referenz hingewiesen wird, aber der Compiler nicht mehr sicher, was sollte die tatsächliche Natur sein kann und daher Sie erhalten eine laxere Referenz wie Class<? extends Feline>
. Dies ist der höchste Wert, den der Compiler von der ursprünglichen Natur des Objekts annehmen kann, und deshalb erhalten wir nur das, was wir bekommen.
Was ist mit neuen Tiger(). GerClass()?
Wir könnten erwarten, dass der einzige Weg, ein Class<Tiger>
(ohne wirldcards) zu erhalten, durch den Zugriff auf das ursprüngliche Objekt sein sollte, nicht wahr? Wie:
Class<Tiger> tigerClass = new Tiger().getClass()
Lustige Sache, obwohl wir immer erreichen das Tiger-Objekt durch einen Referenztyp, richtig ?. In Java haben wir nie direkten Zugriff auf die Objekte. Da wir ein Objekt immer über ihre Referenzen erreichen, kann der Compiler keine Annahmen über den tatsächlichen Typ der zurückgegebenen Referenz machen.
Das ist, warum auch dieser Code Class<? extend Tiger>
Class<? extends Tiger> tigerClass = new Tiger().getClass();
produzieren würde Das heißt, macht der Compiler keine Garantie darüber, was die new
Betreiber hier zurückkehren. Für alles, was wichtig ist, könnte es ein Objekt zurückgeben, das mit Tiger kompatibel ist, aber nicht notwendig, dessen Klasse Tiger selbst ist.
Dies wird deutlicher, wenn Sie den Operator new
für eine Factory-Methode ändern.
TigerFactory factory = new TigerFactory();
Class<? extends Tiger> tigerClass = tigerFactory.newTiger().getClass();
Und unsere Tiger Fabrik:
class TigerFactory {
public Tiger newTiger(){
return new Tiger(){ } //notice this is an anonymous class
}
}
Ich hoffe, das zur Diskussion irgendwie beiträgt.
Ähnliche Frage, aber kein Duplikat! http://stackoverflow.com/questions/20661835/what-is-the-point-of-t-extends-someclass – christopher