1. Rtti:
Mit Laufzeit -Informationen können Sie Typinformationen ermitteln und verwenden, während das Programm ausgeführt wird.
Es gibt zwei Möglichkeiten, Informationen über Objekte und Klassen beim Ausführen von Java zu identifizieren: traditionelles RTTI und Reflexion. Sprechen wir über RTTI.
RTTI: Identifizieren Sie zur Laufzeit den Typ eines Objekts. Dieser Typ muss jedoch zur Kompilierungszeit bekannt sein.
Nehmen wir ein Beispiel, um die Verwendung von RTTI zu sehen. Dies beinhaltet das Konzept des Polymorphismus: Wenn der Code nur auf die Basisklasse verweist und tatsächlich Methoden bestimmter Unterklassen aufgerufen wird, erzeugen normalerweise ein konkretes Objekt (Kreis, Quadrat oder Dreieck, siehe das Beispiel unten), verwandeln Sie es in Form (ignorieren Sie das spezifische Typ des Objekts) und verwenden Sie das Anonymous (dh, dh, nicht das spezifische Typ), in der SUB -SUPPER -SUBER -SUBER -SUBREGEGEBRAUCHE:
Abstract Class Form {// Dies nennt die Methode toString () der aktuellen Klasse und gibt den tatsächlichen Inhalt void Draw () {System.out.println zurück (this + "draw ()"); } // toString () als abstrakte Typ deklarieren, zwingen Sie die Integration, die Methode abstrakt public String toString ();} Klasse Circle zu überschreiben, die Form {public String toString () {return "Circle"; }} Klasse Square erweitert die Form {public String toString () {return "square"; }} Klasse Dreieck erweitert die Form {public String toString () {return "Triangle"; }} public static void main (String [] args) {// Wenn das Formobjekt in das Array von List <Sape> in Form gebracht wird, verliert es in Form, wodurch die spezifische Typinformationsliste <Phaps> Shapelist = Arrays.aslist (New Circle (), New Square (), New Triangle ()) verliert; // Wenn aus dem Array herausgenommen wird, werden alle Elemente dieses Containers als Objekte gehalten und verwandeln das Ergebnis automatisch in Form. Dies ist die grundlegende Verwendung von RTTI. für (Formform: Shapelist) {form.draw (); }}Das Ausgangsergebnis ist:
Circledraw () sadraw () Dreikledraw ()
Bei der Ablagerung in ein Array wird es automatisch in Form transformiert, und der spezifische Typ geht verloren. Wenn Sie aus dem Array herausgenommen werden (der Listenbehälter enthält alles als Objekt), wandelt es das Ergebnis automatisch wieder in Form um. Dies ist die grundlegende Verwendung von RTTI. Alle Typ -Conversions in Java werden zur Laufzeit korrekt überprüft, dh RTTI: Zur Laufzeit identifizieren Sie den Typ eines Objekts.
Die obige Transformation ist nicht gründlich. Wenn die Elemente des Arrays herausgenommen werden, wird das Objekt in Form transformiert, nicht in den spezifischen Typ. Dies geschieht durch Container und Java -Generika -Systeme während der Zusammenstellung, und es gibt Typ -Conversion -Vorgänge, um dies zur Laufzeit sicherzustellen.
Der spezifische Code, der durch ein Formobjekt in eine Unterklasse ausgeführt werden kann, wird durch Polymorphismus bestimmt. Details hängt von dem spezifischen Objekt ab, auf das durch die Formreferenz hingewiesen wird.
Darüber hinaus können Sie mithilfe von RTTI den genauen Typ des Objekts abfragen, auf das durch eine Formreferenz hingewiesen wird, und dann selektiv die Subklass -Methode ausführen.
2. Klassenobjekt:
Um zu verstehen, wie RTTI in Java funktioniert, müssen Sie wissen, wie Typinformationen zur Laufzeit dargestellt werden, was von der Spezialobjektklasse durchgeführt wird.
Klassenobjekte werden verwendet, um alle "regulären" Objekte einer Klasse zu erstellen. Java verwendet Klassenobjekte, um seine RTTI auszuführen.
Immer wenn eine neue Klasse kompiliert wird, wird ein Klassenobjekt (.Class -Datei) generiert. Das JVM, das dieses Programm ausführt, verwendet das Subsystem "Klassenloader".
Klassenlader -Subsystem: Enthält eine Klassenladerkette, jedoch nur einen nativen Klassenlader, der Teil der JVM -Implementierung ist. Lader der nativen Klassenlader laden vertrauenswürdige Klassen, einschließlich Java -API -Klassen, normalerweise aus lokalen Festplatten. Wenn eine Klasse auf eine bestimmte Weise geladen werden muss, um Webserveranwendungen zu unterstützen, können zusätzliche Klassenlader angehängt werden.
2.1. Das Timing des Ladens der Klasse:
Diese Klasse wird geladen, wenn das Programm den ersten Hinweis auf ein statisches Mitglied der Klasse erstellt. Dies beweist, dass der Konstruktor tatsächlich eine statische Methode der Klasse ist. Beim Erstellen eines neuen Objekts der Klasse mit dem neuen Operator wird es auch als Verweis auf das statische Mitglied der Klasse verwendet.
Es ist ersichtlich, dass Java -Programme dynamisch geladen und auf Bedarf geladen werden. Wenn der Unterricht benötigt wird, prüft der Klassenlader zunächst, ob das Klassenobjekt dieser Klasse geladen wurde. Wenn es nicht geladen wurde, findet der Standardklassenloader die .CLASS -Datei basierend auf dem Klassennamen. Als nächstes ist die Überprüfungsphase: Wenn sie geladen werden, akzeptieren sie die Überprüfung, um sicherzustellen, dass sie nicht beschädigt sind und keinen schlechten Java -Code enthalten.
2.2. Klassenbezogene Methoden, NewInstance ()
Das Folgende ist ein Beispiel, um das Laden des Klassenobjekts zu demonstrieren:
Klasse A {// statische Code -Basis, ausgeführt, wenn sie erstmals geladen wird, und ist bekannt, wenn die Klasse durch Druck von Informationen statisch geladen wird. }} Klasse B {static {System.out.println ("Laden b"); }} Klasse C {static {System.out.println ("Laden c"); }} öffentliche Klasse Load {public static void main (String [] args) {System.out.println ("Main ausführen ..."); neu a (); System.out.println ("nach neu a"); try {class.forname ("com.itzhai.test.type.b"); } catch (classNotFoundException e) {System.out.println ("Cloud nicht finden Klasse B"); } System.out.println ("After class.Forname b"); neu c (); System.out.println ("nach neuer C"); }}Das Ausgangsergebnis ist:
Main ausführen ... laden Aafter New Aloading Bafter Class.Forname Bloading Cafter New C
Es ist ersichtlich, dass das Klassenobjekt nur bei Bedarf geladen wird. Beachten Sie hier die Klasse class.Forname ():
Die Methode forname () ist eine Methode, um einen Verweis auf das Klassenobjekt zu erhalten. Wenn Sie die entsprechende Verweise auf das Klassenobjekt erhalten, können Sie zur Laufzeit Typinformationen verwenden.
Wenn Sie bereits ein Interesse an Interesse haben, können Sie die Klassenreferenz erhalten, indem Sie die vom Klassenobjekt bereitgestellte GetClass () -Methode befolgen.
Hier ist ein Code, der von der Klasse verwendet wird:
Schnittstelle x {} Schnittstelle y {} Schnittstelle Z {} Klassenbuchstaben {Buchstaben () {}; Letter (int i) {};} Klasse NewLetter erweitert den Buchstaben implementiert x, y, z {newLerTter () {Super (1); };} public class clasStest { / *** TYP -Informationen drucken. // den Klassennamen system.out.println ("einfacher Name:" + c.GetSimplename ()) erhalten; // Erhalten Sie das voll qualifizierte Klassenname System.out.println ("Kanonischer Name:" + c.GetCanonicalName ()); } public static void main (String [] args) {Klasse c = null; Versuchen Sie {// Die Klasse Referenz c = class.forname ("com.itzhai.test.type.newletter"); } catch (classNotFoundException e) {System.out.println ("Kann nicht com.itzhai.test.type.newletter finden"); System.exit (1); } // Schnittstellen -Typinformationen für (Klasse Gesicht: c.GetInterfaces ()) {printInfo (Gesicht); } // Referenzklasse der Superklasse -Klasse up = C.GetSuperClass (); Objekt obj = null; Versuchen Sie {// Erstellen Sie eine Instanz der Klasse über die NewInstance () -Methode obj = up.newinstance (); } catch (InstantiationException e) {System.out.println ("kann nicht instanziieren"); } catch (illegalAccessException e) {System.out.println ("kann nicht zugreifen"); } // Superklassen -Informationen drucken drucken (obj.getClass ()); }}Die Ausgabe ist:
Klassenname: com.itzhai.test.type.x ist Schnittstelle? TRUESimple Name: Xcanonical Name: com.itzhai.test.type.xclass Name: com.itzhai.test.type.y ist Schnittstelle? TRUESimple Name: Ycanonical Name: com.itzhai.test.type.yclass Name: com.itzhai.test.type.z ist Schnittstelle? TRUEIMPLE NAME: ZCANONISCHER NAME: com.itzhai.test.type.zclass Name: com.itzhai.test.type.letter ist Schnittstelle? falsensimple Name: Lettercanonical Name: com.itzhai.test.type.letter
Beachten Sie, dass die an forname () übergebene Zeichenfolge einen vollständig qualifizierten Namen verwenden muss (einschließlich des Paketnamens).
Durch die in PrintInfo verwendeten Methoden können Sie zur Laufzeit die vollständige Erbschaftsstruktur eines Objekts ermitteln.
Mithilfe der NewInstance () -Methode der Klasse ist dies eine Möglichkeit, einen "virtuellen Konstruktor" zu implementieren, um eine Instanz der Klasse zu erstellen. Die Objektreferenz wird erhalten, zeigt jedoch auf das Buchstabenobjekt, wenn sie verwiesen werden. Klassen, die mit NewInstance () erstellt wurden, müssen einen Standardkonstruktor haben. (Durch die Reflexions -API können Sie jeden Konstruktor verwenden, um Klassenobjekte dynamisch zu erstellen).
2.3. Klasse wörtliche Konstanten:
Neben der Methode GetName () bietet Java auch eine weitere Möglichkeit, einen Verweis auf ein Klassenobjekt zu generieren, dh unter Verwendung von Klassenliteralkonstanten:
NewLerTter.class;
Diese Methode ist einfach und sicher und wird während der Zusammenstellung überprüft, wodurch sie effizienter wird. Es kann nicht nur für gewöhnliche Klassen, sondern auch für Schnittstellen, Arrays und grundlegende Datentypen verwendet werden. Darüber hinaus gibt es für die Wrapper -Klasse des Basistyps auch einen Standardfeldtyp. Das Feld Typ ist eine Referenz, um das entsprechende Objekt der grundlegenden Datentypklassen auszuführen. Aus Gründen der Vereinigung wird empfohlen, das Formular .Class zu verwenden.
2.4. Der Unterschied zwischen der Verwendung von .class und der Verwendung von GetName () zum Erstellen von Objektreferenzen:
Wenn das Klassenobjekt mit .Class erstellt wird, wird es nicht automatisch initialisiert. Die Erstellungsschritte sind wie folgt:
(1) Das Laden wird vom Klassenlader durchgeführt: Schauen Sie sich den Bytecode an (normalerweise im von dem Klassenpfad angegebenen Pfad, aber nicht notwendig) und erstellen Sie dann ein Klassenobjekt aus diesen Bytecodes.
(2) Die Verbindung verifiziert den Bytecode in der Klasse und zuteilt den Speicherplatz für die statische Domäne. Bei Bedarf werden alle Verweise auf andere Klassen dieser Klasse analysiert.
(3) Initialisierung Wenn die Klasse eine Superklasse hat, initialisieren und den statischen Initialisierer- und statischen Initialisierungsblock ausführt.
Die Initialisierung wird bis zur ersten Referenz auf eine statische Methode (der Konstruktor implizit statisch) oder eine statische Nichtnummer-Domäne verzögert:
Klassendaten1 {statische endgültige int a = 1; statische endgültige doppelte b = math.random (); static {System.out.println ("init data1 ..."); }} class Data2 {static int a = 12; static {System.out.println ("init data2 ..."); }} Klasse Data3 {static int a = 23; static {System.out.println ("init data3 ..."); }} public class classtest2 {public static void main (String [] args) {System.out.println ("Data1.class:"); Klassendaten1 = data1.class; System.out.println (data1.a); // data1 system.out.println (data1.b); // data1 initialisierte System.out.println (data2.a); // Data2 Initialisierte Try {class Data3 = class.Forname ("com.itzhai.test.type.data3"); // data3 initialisierte} catch (classNotFoundException e) {System.out.println ("Kann nicht Com.itzhai.test.type.data3 ..."); } System.out.println (data3.a); }}Das Ausgangsergebnis ist:
Data1.Class: 1Init Data1 ... 0.26771085109184534init Data2 ... 12Init Data3 ... 23
Die Initialisierung erreicht effektiv so "faul" wie möglich.
2.5. Im Folgenden finden Sie einige Situationen, um festzustellen, ob die Initialisierung durchgeführt werden soll:
(1) Die Klassensyntax erhält einen Verweis auf die Klasse und verursacht keine Initialisierung;
(2) class.Forname () generiert eine Klassenreferenz und wird sofort initialisiert;
(3) Wenn ein statischer Endwert eine "Compiler -Konstante" ist, kann dieser Wert ohne Initialisierung der Klasse gelesen werden.
(4) Es reicht nicht aus, dieses Verhalten zu gewährleisten, wenn nur eine Domäne auf statisches Finale festgelegt wird, beispielsweise:
statische endgültige doppelte b = math.random ();
(5) Wenn eine statische Domäne Bushifinal ist, müssen Sie beim Zugang immer fortgeschrittener Verknüpfung und initialisiert werden.
2.6. Verallgemeinerter Klassenzitat:
Eine Klassenreferenz repräsentiert den genauen Typ des Objekts, auf das sie verweist, und das Objekt ist ein Objekt der Klassenklasse. In Javase5 kann das Klassenobjekt, auf das eine Klassenreferenz verweist, nach Generika qualifiziert werden, und der Compiler kann zusätzliche Typprüfungen durchsetzen:
Klasse intcls = int.class; // Generika verwenden, um die Referenz zu definieren, auf die die Klasse Class <Integer> Genintcls = int.Class; // Klasse ohne Generika gezeigt werden kann, kann neu zugewiesen werden, um auf ein anderes Klassenobjekt intcls = double.class; // Die folgende Kompilierung zu verweisen // Genintcls = double.classe;
2.6.1. Wildcards verwenden? Entspannen Sie die Grenzen der Generika:
Klasse <?> Intcls = int.class; intcls = string.class;
In Javase5 ist die Klasse <?> Besser als die gewöhnliche Klasse, und es wird empfohlen, die Klasse <?> Zu verwenden, auch wenn sie gleichwertig sind, da der Vorteil der Klasse <?> Ist, dass Sie nicht stattfinden oder fahrlässig sind, sondern eine nicht spezifische Klassenreferenz verwenden.
Um einen Verweis auf die Klasse auf einen bestimmten Typ zu definieren, oder ein Subtyp dieses Typs kann Wildcards mit Erweiterungen verwenden, erstellen Sie einen Bereich:
Klasse <? Erweitert die Zahl> num = int.class; // Der Referenzbereich von Num ist die Zahl und seine Unterklasse, sodass Sie die Wertnummer = double.class zuweisen können. num = number.class;
2.6.2. Die NewInstance () -Methode unter Generika:
Unter Verwendung der Klasse nach Generika ist das Objekt, das durch Aufrufen von NewInstance () zurückgegeben wird, vom genauen Typ. Wenn Sie jedoch die GotuperClass () verwenden, um die Superklasse dem Generika zu erhalten, gibt es einige Einschränkungen für den realen Typ: Der Compiler weiß, dass die Art der Superklasse während der Kompilierungsperiode zurückgibt.
Hund Hund = dogcls.newinstance (); Abstract Class Animal {} Klasse Dog erweitert Tier {} // Die folgende Schreibmethode ist falsch und kann nur die Klasse <? Super Dog> Typ // Class <Antiere> Animalcls = dogcls.getSuperClass (); Klasse <? Super Dog> Animalcls = dogcls.getSuperClass (); // Durch die erhaltene Superklasse Referenz können Sie nur Objekte erstellen, die Objekttypobjekt Obj = Animalcls.Newinstance () zurückgeben; 2.6.3. Neue Transformationssyntax: cast () Methode
Schauen Sie sich den Code direkt an:
Animal Animal = New Dog (); Klasse <hund> dogcls = hunde.class; Hundehund = Dogcls.cast (Tier); // oder direkt die folgende Transformationsmethode Dog = (Dog) Tier;
Es ist festzustellen, dass die Verwendung der Cast () -Methode zusätzliche Arbeiten erledigt hat. Diese Conversion -Methode kann in der folgenden Situation verwendet werden: Wenn Sie eine generische Band schreiben, können Sie die Methode cast () verwenden, wenn eine Klassenreferenz gespeichert wird und Sie die Transformation durch diese Klassenreferenz durchführen.
3. Typ Check -Instanzof
3.1. Überprüfen Sie vor der Konvertierung vor dem Typ
Mit dem Compiler können Sie ohne angezeigte Transformationsvorgänge freie Transformationszuweisungsvorgänge frei durchführen, genau wie das Zuweisen von Werten für Referenzen auf Superklassen.
Wenn die angezeigte Typumwandlung jedoch nicht verwendet wird, können Sie mit dem Compiler nicht die Downconversion -Zuordnung durchführen. Zu diesem Zeitpunkt können wir auch prüfen, ob das Objekt eine Instanz eines bestimmten Typs und die Schlüsselwortinstanz des Schlüsselworts ist:
if (x Instanz des Hundes) ((Hund) x) .Bark ();
3.2. Die Form von RTTI:
Bisher wissen wir also, dass die Formen von RTTI: umfassen:
(1) herkömmliche Typumwandlung (Form)
(2) Klassenobjekt, das den Typ des Objekts darstellt
(3) Schlüsselwortinstanz
3.3. Dynamische Instanzmethode:
Die Klasse. Issinstance -Methode bietet eine Möglichkeit, Objekte dynamisch zu testen.
Das Folgende zeigt die Verwendung von Instanz und Klasse. Issinstance:
Attribut:
öffentliches Schnittstellenattribut {}Form:
/** * Erstellen Sie eine abstrakte Klasse */public abstract Class Form {// Dies nennt die TOString -Methode der aktuellen Klasse -ToString -Methode, um Informationen public void Draw () {System.out.println (this + ".draw ()") zu erhalten; } // Deklarieren Sie die Methode toString () zum Zusammenfassung und zwingen den Erben, die Methode neu zu schreiben. Abstract Public String toString ();}Kreis:
Der öffentliche Klassenkreis erweitert Form implementiert Attribut {public String toString () {return "circle"; }}Quadrat:
öffentlicher Klasse Square erweitert die Form {public String toString () {return "Square"; }}Dreieck:
öffentliches Klassendreieck erweitert die Form {public String toString () {return "Triangle"; }}Geben Sie die Überprüfung ein:
// InstanceOfcircle c = neuer Circle (); // Bestimmen Sie, ob die Instanz von Superclass -System.out.Format ("Instanz: %S ist eine Form? %b/n", c.toString (), c Instanzform); // Bestimmen Sie, ob die Instanz des Supercass -Systems. Kreis); // Bestimmen Sie, ob die Instanz von Supercass -System.out.Format ("unter Verwendung von Klasse.ISInstance: %S eine Form? %B/n", C.ToString (), c Instanz des Kreises); // Bestimmen Sie, ob die Instanz von Supercass -System.Out.Out.Format ("unter Verwendung von class.issinstance: %s ist eine Form? Shape.class.issinstance (c)); // Die Instanz der Bestimmung, ob die Schnittstelle system.out.format ("Verwendung von class.issinstance: %S ist ein Attribut? %B/n", C.ToString (), Attribut.Class.issinstance (c));Es kann festgestellt werden, dass die Instanz oder die Klasse. Issinstance -Methode bestimmt, ob eine Instanz des Systems erben, dh zusätzlich zur Beurteilung selbst bestimmt, ob es sich um eine Superklasse oder eine Instanz einer Schnittstelle handelt.
Das Folgende zeigt, wie die dynamische Klasse verwendet wird.
Erstellen Sie zunächst eine abstrakte Formgeneratorklasse:
public abstract Class Shapecreator {private random rand = new random (10); // Geben Sie eine Reihe von Objekttypen zurück, die von der Implementierungsklasse bereitgestellt werden. Sie werden später zwei Implementierungsformulare sehen, basierend auf Forname und basierend auf der Klassenliteralkonstanten. Klassenklasse öffentliche abstrakte Liste <Klasse <Klasse <? erweitert Form >> Typen (); // generieren Sie zufällig eine Typ -Objektinstanz in einer Reihe von Objekttypen öffentlich Form randomShape () {int n = rand.nextint (Typen (). Size ()); Versuchen Sie {return type (). get (n) .Newinstance (); } catch (InstantiationException e) {e.printstacktrace (); null zurückkehren; } catch (illegalAccessException e) {e.printstacktrace (); null zurückkehren; }} // generieren Sie ein zufälliges Array public Form [] createarray (int size) {form [] result = new Shape [Größe]; für (int i = 0; i <size; i ++) {result [i] = randomShape (); } Rückgabeergebnis; } // ein zufälliges Array generieren, eine generische ArrayList Public ArrayList <Sapary> ArrayList (int -Größe) {ArrayList <Sapary> result = new ArrayList <Phaper> (); Collections.Addall (Ergebnis, Createarray (Größe)); Rückgabeergebnis; }}Schreiben Sie als nächstes eine Implementierung dieser abstrakten Klasse:
/** * Forname Generator Implementierung * @author artinking * */public class fornamecreator erweitert Shapecreator {private statische Liste <Klasse <Class <? Erweitert Form >> Typen = NeuarrayList <Klasse <? erweitert die Form >> (); Private Static String [] typenames = {"com.itzhai.javanote.entity.circle", "com.itzhai.javanote.entity.square", "com.itzhai.javanote.entity.Triangle"}; @Suppresswarnings ("unbenutzt") private static void loader () {für (String -Name: typeNames) {try {type.add ((Klasse <? Erweitert Form>) class.forname (Name)); } catch (classNotFoundException e) {e.printstacktrace (); }}} // initialisieren Sie das Array von Typen, die zum Laden static {lader () erforderlich sind; } öffentliche Liste <Klasse <? Erweitert Form >> Typen () {Rückgabe -Typen; }}Schreiben Sie schließlich eine Klasse, die die Anzahl der Formen unter Verwendung eines Instanzes zählt:
public class ShapeCount {statische Klasse ShapeCounter erweitert HashMap <String, Integer> {public void count (String -Typ) {Integer Quantity = get (type); if (quantity == null) {put (type, 1); } else {put (Typ, Menge + 1); }}} // Angaben zu Objekttypen durch das Instanz von Keyword Public static void countshapes (Shapecreator Creator) {Shapecounter counter = new Shapecounter (); für (Formform: Creator.Createarray (20)) {if (Forminstanz des Kreises) Counter.count ("Kreis"); if (forminstanz von quadratisch) count.count ("quadratisch"); if (Forminstanz von Dreieck) {counter.count ("Triangle"); }} System.out.println (Zähler); } public static void main (String [] args) {countShapes (neuer fornamecreator ()); }}Schreiben Sie die Implementierung der abstrakten Klasse neu und implementieren Sie sie mit Klassenliteralkonstanten erneut:
/*** Implementierung von Literalgenerator*/öffentliche Klasse Literalcreator erweitert Shapecreator {öffentliche statische endgültige Liste <Klasse <Klasse <? erweitert Form >> AllType = collections.unmodifiablelist (Arrays.aSlist (Circle.Class, Triangle.Class, Square.class)); Öffentliche Liste <Klasse <? erweitert Form >> Typen () {return AllType; } public static void main (String [] args) {System.out.println (AllType); }}Verwenden Sie nun Class.instance, um die Anzahl der Formen wie folgt zu zählen:
/*** Entfernen Sie die monotonische Instanzanweisung in der ursprünglichen ShapeCount unter Verwendung von Class.instanceof Dynamic Test Object***/Public Class ShapeCount2 {private statische endgültige Liste <Klasse <Klasse <? Erweitert Form >> Shapetypen = literalcreator.AllType; statische Klasse ShapeCounter erweitert HashMap <String, Integer> {public void count (String -Typ) {Integer quantity = get (type); if (quantity == null) {put (type, 1); } else {put (Typ, Menge + 1); }}} // Demonstrieren Sie die statistischen Objekttypen über class.issinstance () public static void countshapes (Shapecreator Creator) {Shapecounter counter = new Shapecounter (); für (Formform: Creator.Createarray (20)) {für (Klasse <? Erweitert Form> cls: Shapetypes) {if (cls.Instance (Form)) {count.count (cls.getSimplename ()); }} System.out.println (Zähler); } public static void main (String [] args) {countShapes (neuer fornamecreator ()); }}Jetzt gibt es zwei Implementierungen des Generators. Wir können hier eine Erscheinungsebene hinzufügen und die Standard -Implementierungsmethode festlegen:
/*** Jetzt gibt es zwei Implementierungen des Generators. Fügen wir hier eine Erscheinungsebene hinzu und setzen Sie die Standard -Implementierungsmethode */öffentliche Klasse Formen {public statische endgültige Shapecreator Creator = new LiteralCreator (); öffentliche statische Form randomShape () {return creator.randomshape (); } public static form [] createarray (int size) {return Creator.Createarray (Größe); } public static ArrayList <Phapy> ArrayList (int Größe) {return creator.ArrayList (Größe); }} 3.4. Äquivalenz von Instanz und Klasse:
Das von Instanz und Isinstance () generierte Ergebnis ist genau das gleiche, wobei das Konzept des Typs beibehält und festgelegt wird, ob eine Klasse oder eine abgeleitete Klasse dieser Klasse.
Equals () ist dasselbe wie ==, und die Verwendung dieses praktischeren Klassenobjekts wird die Vererbung nicht berücksichtigt.
System.out.println (New Circle () Instanz des Kreises); // treesystem.out.println (form.class.issinstance (New Circle ())); // treesystem.out.println ((neuer Circle ()). getClass () == Circle.class); // tuesystem.out.println ((neuer Kreis (). getClass ()). Equals (Shape.Class)); // FALSCH