Dieser Artikel zielt darauf ab, eine umfassende Einführung in den Java -Reflexionsmechanismus zu geben. Ich hoffe, dass Sie durch diesen Artikel ein umfassendes Verständnis für den relevanten Inhalt der Java -Reflexion haben.
Bevor Sie diesen Artikel lesen, können Sie sich auf " Wiederverständnis von Java Generics " beziehen.
Vorwort
Der Java -Reflexionsmechanismus ist eine sehr starke Funktion. Reflexionen sind in vielen großflächigen Projekten wie Frühling und MyBatis zu sehen. Durch den Reflexionsmechanismus können wir während des Betriebs Objekttypinformationen erhalten. Mit dieser Funktion können wir Entwurfsmuster wie den Werksmodus und den Proxy -Modus implementieren und auch Bedrängnisprobleme wie Java Generic Löschen lösen. In diesem Artikel werden wir den Java -Reflexionsmechanismus aus der Perspektive praktischer Anwendungen anwenden.
Reflexionsbasis
PS: In diesem Artikel müssen die Leser ein gewisses Maß an Verständnis der Reflexionsmechanismus -API haben. Wenn Sie es zuvor noch nicht ausgesetzt waren, wird empfohlen, zuerst den schnellen Start des offiziellen Dokuments zu betrachten.
Bevor Sie den Reflexionsmechanismus anwenden, schauen wir uns zunächst an, wie die Class einem Objekt entspricht. In Java haben wir drei Möglichkeiten, die Reflexionsklasse eines Objekts zu erhalten.
Durch GetClass -Methode
In Java verfügt jedes Object über eine getClass -Methode. Durch die GetClass -Methode können wir die entsprechende Reflexionsklasse dieses Objekts erhalten:
String S = "Ziwenxie"; Klasse <?> C = S.GetClass ();
Wir können auch die statische Methode forName Class nennen:
Klasse <?> C = class.forname ("java.lang.String"); Oder wir können .class direkt verwenden:
Klasse <?> C = string.class;
Zu Beginn des Artikels haben wir erwähnt, dass einer der Hauptvorteile der Reflexion darin besteht, dass wir während des Betriebs Objekttypinformationen erhalten können. Schauen wir es uns mit einem Beispiel ausführlich an.
Zunächst erstellen wir eine neue Schnittstelle A unter typeinfo.interfacea -Paket:
Paket typeInfo.Interfacea; öffentliche Schnittstelle a {void f (); } Anschließend erstellen wir eine neue Schnittstelle C unter dem Paket typeinfo.packageaccess . Die Schnittstelle C erbt von der Schnittstelle A , und wir haben auch mehrere andere Methoden zum Testen erstellt. Beachten Sie, dass die Berechtigungen der folgenden Methoden unterschiedlich sind.
Paket typinfo.packageAccess; Import typinfo.interfacea.a; Klasse C implementiert einen {public void f () {System.out.println ("public cf ()"); } public void g () {System.out.println ("public cg ()"); } protected void v () {System.out.println ("Protected CV ()"); } void u () {System.out.println ("Paket cu ()"); } private void w () {System.out.println ("privat cw ()"); }} öffentliche Klasse Hiddenc {public static a makea () {return New C (); }} In callHiddenMethod() -Methode verwenden wir mehrere neue APIs, wobei getDeclaredMethod() eine Methode erhalten wird, mit der sich die Klasse der Klasse auf das Objekt gemäß dem Method -Namen bezieht, und dann können wir die zugehörigen Methoden des Objekts durch Aufrufen invoke() -Methode auslösen:
Paket typinfo; typinfo.Interfacea.a; importtypinfo.packageacess.hiddenc; import Java.lang.reflect.Method; öffentliche Klasse HidDedImplementation {public static void main (String [] args) löst eine Ausnahme aus {a = hiddenc.makea.makea (); af (); System.out.println (A.getClass (). GetName ()); // oops! Nachdenken ermöglicht es uns immer noch, G () anzurufen: callhiddenMethod (a, "g"); // und sogar Methoden, die weniger zugänglich sind! callhiddenMethod (a, "u"); callhiddenMethod (a, "v"); callhiddenMethod (a, "w"); } static void callHiddenMethod (Objekt A, String methodName) löst Ausnahme aus {Methode g = a.getClass (). getDeclaredMethod (methodName); g.setAccessible (wahr); g.invoke (a); }} Aus den Ausgabeergebnissen können wir sehen, dass wir sie durch die Reflexionsklasse frei nennen können, ob es sich um public , default , protect oder pricate -Methode handelt. Natürlich müssen wir nur die starke Kraft der Reflexion zeigen, und diese Technik wird in der tatsächlichen Entwicklung nicht empfohlen.
public vgl
Wir haben das folgende Geschäftsszenario. Wir haben eine generische List<Class<? extends Pet>> . Wir müssen zählen, wie viele spezifische Pet in dieser Sammelklasse sind. Aufgrund des generischen Java -Löschens ist es definitiv nicht möglich, die ähnliche Praxis zu achten, die die List<? extends Pet> , da der JVM nach der statischen Typ -Überprüfung alle Objekte in der Sammlung während des Laufs als Pet behandelt. Es wird jedoch nicht wissen, ob Pet Cat oder Dog repräsentiert, sodass die Typinformationen des Objekts während des Laufs tatsächlich verloren gehen. PS: Über generisches Löschen: Ich habe eine detaillierte Erklärung im vorherigen Artikel. Interessierte Freunde können einen Blick darauf werfen.
Um unser obiges Beispiel zu implementieren, definieren wir zunächst mehrere Klassen:
public class pet erweitert individual {public pet (String name) {super (name); } public pet () {super (); }} öffentliche Klasse Cat erweitert PET {public Cat (String -Name) {Super (Name); } public Cat () {Super (); }} public class hund erweitert pet {public hunde (String name) {Super (name); }} public class ägyptisch erweitert Cat {public ägyptianmau (String name) {super (name); } public ägyptianmau () {Super (); }} public class Mutt erweitert den Hund {public mutt (String name) {Super (name); } public mutt () {Super (); }} Pet erbt vom Individual . Die Implementierung Individual Klasse ist etwas komplizierter. Wir haben Comparable Schnittstelle implementiert und die Klassenvergleichsregeln neu definiert. Wenn wir es nicht sehr gut verstehen, spielt es keine Rolle. Wir haben es abstrahiert, daher spielt es keine Rolle, ob wir das Implementierungsprinzip nicht verstehen.
Einzelpersonen im öffentlichen Klassen vergleichbar <individual> {private statische lange Zähler = 0; private endgültige lange ID = Zähler ++; privater Zeichenfolge Name; // Name ist optional public individual (String -Name) {this.name = name; } public individual () {} public String toString () {return getClass (). GetImplename () + (name == null? "": "" + name); } public Long id () {return id; } public boolean Equals (Objekt o) {return o Instance von individual && id == ((individual) o) .id; } public int HashCode () {int result = 17; if (name! = null) {result = 37 * result + name.hashcode (); } result = 37 * result + (int) id; Rückgabeergebnis; } public int vergleicheto (individual arg) {// Vergleiche nach Klassenname zuerst: String first = getClass (). getImpleName (); String argfirst = arg.getClass (). GetImleName (); int firstCompare = first.comPareto (argfirst); if (FirstCompare! = 0) {return firstCompare; } if (name! = null && arg.name! if (SecendCompare! = 0) {return secondaryCompare; }} return (arg.id <id? -1: (arg.id == id? 0: 1)); }} Unten finden Sie eine abstrakte Klasse PetCreator . In Zukunft können wir direkt die Sammlung verwandter Pet -Klassen erhalten, indem wir arrayList() aufrufen. Hier verwenden wir die newInstance() -Methode, die wir oben nicht erwähnt haben. Es wird eine Instanz der Klasse zurückgeben, auf die sich die Klasse wirklich bezieht. Was bedeutet das? Zum Beispiel sind es gleichwertig, new Dog().getClass().newInstance() und Direct new Dog() .
public abstract Class PetCreator {private random rand = new random (47); // Die Liste der verschiedenen Gettypen von PET zu erstellen: öffentliche abstrakte Liste <Klasse <? erweitert PET >> Gettypes (); public pet randompet () {// Erstellen eines zufälligen PET int n = rand.nextint (GettTypes (). size ()); Versuchen Sie {return gettTypes (). Get (n) .Newinstance (); } catch (InstantiationException e) {neue runTimeException (e) werfen; } catch (illegalAccessException e) {neue runTimeexception (e) werfen; }} public pet [] createarray (int size) {pet [] result = new Pet [Größe]; für (int i = 0; i <size; i ++) {result [i] = randompet (); } Rückgabeergebnis; } public ArrayList <Pet> ArrayList (int Größe) {ArrayList <Pet> result = new ArrayList <Pet> (); Collections.Addall (Ergebnis, Createarray (Größe)); Rückgabeergebnis; }} Lassen Sie uns als nächstes die obige abstrakte Klasse implementieren und den folgenden Code erläutern. Im folgenden Code deklarieren wir zwei Sammelklassen, allTypes und types , unter denen allTypes alle oben deklarierten Klassen enthält, aber unsere spezifischen Typen sind eigentlich nur zwei Typen, nämlich Mutt und EgypianMau , sodass das Haustier, das wir wirklich benötigen, um new zu erhalten, nur die Typen, die in types enthalten sind. In Zukunft können wir die in types enthaltenen Typen erhalten, indem wir getTypes() aufrufen.
öffentliche Klasse LiteralPetCreator erweitert PetCreator {@Suppresswarnings ("Deaktiviert") öffentliche statische endgültige Liste <Klasse <Klasse <? erweitert PET >> AllTypes = Collections.unmodifiablelist (arrays.aslist (pet.class, dog.class, cat.class, mutt.class, ägyptianmau.class)); private statische endgültige Liste <Klasse <? erweitert PET >> Typen = AllTypes.Sublist (AllTypes.Indexof (Mutt.Class), AllTypes.size ()); Öffentliche Liste <Klasse <? erweitert PET >> GettTypes () {Rückgabe -Typen; }} Die Gesamtlogik wurde abgeschlossen, und schließlich implementieren wir TypeCounter -Klasse, mit der die Anzahl der relevanten Pet -Klassen im Satz zählt. Erklären Sie isAssignalbeFrom() -Methode, die bestimmen kann, dass eine Reflexionsklasse eine Unterklasse oder eine indirekte Unterklasse einer Reflexionsklasse ist. Wie der Name schon sagt, soll getSuperclass() die übergeordnete Klasse einer Reflexionsklasse erhalten.
public class typeCounter erweitert HashMap <class <?>, Integer> {private class <?> Basetype; public typeCounter (class <?> baseType) {this.basetype = baseType; } public void count (Objekt obj) {class <?> type = obj.getClass (); if (! baseType.issignableFrom (Typ)) {neue RunTimeException (OBJ + "Falscher Typ" + Typ + "werfen, sollte Typ oder Subtyp von" + BaseType) sein; } CountClass (Typ); } private void countClass (Klasse <?> Typ) {Integer quantity = get (type); put (Typ, Menge == NULL? 1: Menge + 1); Klasse <?> SuperClass = type.getSuperClass (); if (superklasse! = null && baseType }} @Override public String toString () {StringBuilder result = new StringBuilder ("{"); für (map.entry <class <?>, Integer> pair: Eintragset ()) {result.append (pair.getKey (). GetImpleName ()); result.append ("="); result.Append (pair.getValue ()); result.Append (","); } result.delete (result.length () - 2, result.Length ()); result.append ("}"); Rückgabeergebnis.ToString (); }}Zusammenfassen
Das obige ist der gesamte Inhalt dieses Artikels über den Beispielcode -Austausch des Java -Reflexionsmechanismus, und ich hoffe, dass es für alle hilfreich sein wird. Interessierte Freunde können weiterhin auf diese Seite verweisen:
Java -Programmier- und Druckeinkäufe -Implementierungscode
Detaillierte Erläuterung der Implementierung von Referenzen und dynamischen Proxy in Java
Java -Programmierung zur Implementierung der einfachen Code -Freigabe von Mondfinsternis
Wenn es Mängel gibt, hinterlassen Sie bitte eine Nachricht, um darauf hinzuweisen. Vielen Dank an Freunde für Ihre Unterstützung für diese Seite!