Was ist Reflexion
"Reflection ermöglicht es Programmen, die im JVM ausgeführt werden, das Verhalten der Laufzeit zu erkennen und zu ändern." Dieses Konzept ist oft mit Selbstbeobachtung verwechselt. Hier sind die Erklärungen dieser beiden Begriffe in Wikipedia:
Beispiel für Selbstbekämpfung: Der Instanzoperator wird verwendet, um festzustellen, ob ein Objekt zu einer bestimmten Klasse gehört.
if (obj Instance von Hund) {Hund D = (Hund) obj; D.Bark ();}Reflexionsbeispiel: Die Methode class.Forname () kann das entsprechende Klassenobjekt über den Namen der Klasse oder Schnittstelle (eine Zeichenfolge oder ein vollständig qualifizierter Name) erhalten. Die Forname -Methode löst die Initialisierung der Klasse aus.
// Reflection Class <?> C = class.forname ("classPath.and.className"); Object Dog = C.Newinstance ();In Java ist die Reflexion näher an der Selbstbeobachtung, da Sie die Struktur eines Objekts nicht ändern können. Obwohl einige APIs verwendet werden können, um die Sichtbarkeit von Methoden und Eigenschaften zu ändern, können sie Strukturen nicht ändern.
Reflexion von Arrays
Was nutzt die Reflexion eines Arrays? Wann müssen Sie die Reflexion von Arrays verwenden? Schauen wir uns den folgenden Code an:
Integer [] nums = {1, 2, 3, 4}; Objekt [] objs = nums; // Es kann automatisch in Integer [] in Object [] Objekt obj = nums konvertiert werden; // Integer [] ist natürlich ein Objekt int [] ids = {1, 2, 3, 4}; // Objekt [] objs2 = ids; // Die int [] kann nicht in Objekt [] Objekt obj2 = ids konvertiert werden; // int [] ist ein ObjektDas obige Beispiel zeigt, dass ein grundlegender Typ eines eindimensionalen Arrays nur als Objekt angesehen werden kann, nicht als Objekt [].
int [] [] intarrray = {{1, 2}, {3, 4}}; Objekt [] oa = intarrray; Objekt obj = intarrray; // Integer [] [] IntegerArray = intarrray; int [] [] nicht integer [] [] Integer [] [] IntegerArray2 = new Integer [] [] {{{1, 2}, {3, 4}}; Objekt [] [] oa2 = IntegerArray2; Objekt [] oa3 = IntegerArray2; Objekt obj2 = IntegerArray2;Aus dem obigen Beispiel können wir sehen, dass das zweistellige Array von Java ein Array von Arrays ist. Werfen wir einen Blick auf das Beispiel, ein Array zu reflektieren:
Paket cn.zq.array.reflect; Import Java.lang.reflect.Array; Import Java.util.Arrays; import Java.util.random; public class arrayreflect {public static void main (String [] args) {random rand = new random (47); int [] ist = new int [10]; für (int i = 0; i <is.Length; i ++) {is [i] = Rand.Nextint (100); } System.out.println (IS); System.out.println (Arrays.aslist (IS)); /*Die beiden oben genannten Ausgänge sind ähnliche Zeichenfolgen wie "[[i@14318BB]", die den im Array gespeicherten Inhalt nicht anzeigen können. Natürlich verwenden wir das Traversal, um den Inhalt im Array*/ system.out.println ("-1. Durchqueren zum Array durch Drucken-") auszugeben. für (int i = 0; i <is.Length; i ++) {System.out.print (ist [i]+""); } System.out.println (); System.out.println ("-2. Überqueren zum Array durch Drucken-"); Objekt obj = ist; // das eindimensionale Int-Array in Object System.out.println ("obj isArray:" + obj.getClass (). Isarray ()) konvertieren; für (int i = 0; i <array.getLength (obj); i ++) {int num = array.getInt (obj, i); // Sie können diese häufig verwendete Methode auch verwenden, um den Wert der entsprechenden Indexposition zu erhalten // Objekt value = array.get (obj, i); // Wenn das Array den Basistyp speichert, entspricht der Wrapper -Typ, der dem grundlegenden Typ system.out.print (num + "") entspricht. }}}Ausgabe:
[I@14318BB [[I@14318BB] - -1. Drucken Sie das Array, indem Sie das Array mit herkömmlichen Mitteln durchqueren-58 55 93 61 61 29 68 0 22 7-2. Drucken Sie das Array, indem Sie das Array durchqueren, indem Sie das Array durchqueren, indem Sie das Array-Obj Isarray durchqueren: True 58 55 93 61 61 29 68 0 22 7
Das obige Beispiel schafft zuerst ein eindimensionales Array von int und füllt dann zufällig eine Ganzzahl von 0 ~ 100. Wenn Sie das Array dann direkt über die Methode system.out.println () ausgeben oder die Methode der Arrays.aSlist verwenden (wenn es sich nicht um ein eindimensionales Array von Grundtypen handelt, kann diese Methode wie erwartet in die Liste konvertiert werden. Wenn es sich um ein zweidimensionales Array handelt, kann es nicht wie erwartet auf Liste konvertiert werden). Das Array wird in die Liste und dann in die Ausgabe konvertiert, und das Übergeben ist nicht das Ausgabeergebnis, das wir erwarten. Als nächstes werden die Inhalte im Array in einer regulären Array -Traversal -Methode ausgegeben und dann int [] als Objekt behandelt und verwenden Reflexion, um seinen Inhalt zu durchqueren. Class.isArray () kann verwendet werden, um festzustellen, ob ein Objekt ein Array ist. Wenn es sich um ein Array handelt, werden die relevanten Informationen des Arrays über java.lang.reflect.array erhalten, eine Werkzeugklasse, die das Array widerspiegelt. In dieser Klasse werden einige GET-Methoden verwendet, um die Länge des Arrays zu erhalten, von denen jede Version verwendet wird, um den entsprechenden Index des eindimensionalen Arrays grundlegender Typen, eine allgemeine Methode zum Erhalt des Wertes (Objektarray, Int-Index), eine Methode zum Einstellen des Werts und zwei Methoden zum Erstellen von Arrayinstanzen zu erhalten. Durch die Array Reflection Tools -Klasse ist es einfach, Array -Reflexion zu verwenden, um allgemeine Code zu schreiben, ohne zu beurteilen, welcher Grundtyp des Arrays das angegebene Array ist.
Paket cn.zq.array.reflect; Import Java.lang.reflect.Array; öffentliche Klasse NewArrayInstance {public static void main (String [] args) {Objekt o = array.newinstance (int.class, 20); int [] ist = (int []) o; System.out.println ("is.length =" + is.Length); Objekt O2 = Array.NewinStance (int.Class, 10, 8); int [] [] iss = (int [] [] []) O2; System.out.println ("iss.length =" + iss.Length + ", ISS [0] .Lenght =" + iss [0] .Length); }} is.length = 20 iss.length = 10, iss [0] .lenght = 8 Array hat 2 Methoden übergeben, um ein Array zu erstellen
Objekt NewInstance (Klasse <?> ComponentType, int Länge), erstellen Sie ein Array der angegebenen Länge basierend auf der vorgesehenen Klasse. Wenn int.Class wie oben angegeben ist, beträgt die Länge 10, was dem neuen INT entspricht [10];
Object NewInstance (Klasse <?> ComponentType, int ... Dimensionen) erstellt ein Array, das auf den bereitgestellten Klasse und Abmessungen basiert. Die variablen Parameterabmessungen werden verwendet, um die Länge jeder Dimension des Arrays anzugeben. Wie im obigen Beispiel ist es gleichbedeutend mit der Erstellung eines zweidimensionalen Arrays neuer INT [10] [8], kann jedoch kein mehrdimensionales Array mit unterschiedlichen Längen jeder Dimension erzeugen. Durch die erste Methode zum Erstellen eines Arrays können Sie ein solches Array erstellen. Objekt o = Array.NewinStance (int []. Klasse, 20) kann verwendet werden, um ein zweidimensionales Array zu erstellen, das dem Objekt o = new int [20] [] entspricht;
Natürlich ist es selten, das obige Beispiel zu verwenden, um ein Array zu erstellen, aber es ist tatsächlich überflüssig. Warum nicht ein Array direkt durch neu erstellen? Reflection erzeugt ein Array nicht nur schneller als neu, sondern auch das geschriebene Programm ist nicht einfach zu lesen, daher ist es nicht so direkt wie neu. Tatsächlich ist es wirklich selten, Arrays durch Reflexion zu erzeugen. Welche Art von abnormalen Bedürfnissen gibt es, um Reflexion zu verwenden, um Arrays zu erstellen!
Da bei der Ausgabe einer Array von Grundtypen einige Hindernisse aufgetaucht waren, verwendet Folgendes Array -Reflexion, um eine Werkzeugklasse zu implementieren, um die gewünschte Ausgabe zu erreichen:
Paket cn.zq.util; importieren java.io.BytearrayoutputStream; importieren java.io.printstream; Import Java.lang.reflect.Array; public class print {public static void print (Objekt obj) {print (obj, system.out); } public static void print (Objekt obj, printstream out) {out.println (getPrintstring (obj)); } public static void println () {print (system.out); } public static void println (printstream out) {out.println (); } public static void printNB (Objekt obj) {printNB (obj, System.out); } public static void printNB (Objekt obj, printstream out) {out.print (getPrintstring (obj)); } öffentliches statisches Printstream -Format (String -Format, Objekt ... Objekte) {return format (System.out, Format, Objekte); } public static printStream -Format (printstream out, String -Format, Objekt ... Objekte) {Objekt [] handleObjects = new Object [Objects.length]; für (int i = 0; i <Objekte if (Object == null || isPrimitiveWrapper (Object)) {HandleObjects [i] = Objekt; } else {bytearrayoutputStream bos = new bytearrayoutputStream (); Printstream ps = neuer printstream (bos); printNB (Objekt, PS); ps.close (); HandleObjects [i] = new String (bos.tobytearray ()); }} out.format (format, handleObjects); zurückkehren; } /*** Bestimmen Sie, ob ein bestimmtes Objekt eine Wrapper -Klasse des Basistyps ist. * @Param o Gebenes Objekt * @return Wenn es sich um eine Wrapper -Klasse von primitiven Typen handelt, geben Sie Ja zurück, ansonsten return No. o Instanz des Booleschen || o Instanz des Charakters || o Instanz von Byte || o Instanz von kurz || o Instanz der Ganzzahl || o Instanz von langer || o Instanz des Floats || o Instanz von Doppel; } public static String getPrintString (Objekt obj) {StringBuilder result = new StringBuilder (); if (obj! = null && obj.getClass (). isArray ()) {result.append ("["); int len = array.getLength (obj); für (int i = 0; i <len; i ++) {Object value = array.get (obj, i); result.Append (getPrintString (Wert)); if (i! = len - 1) {result.append (","); }} result.append ("]"); } else {result.append (string.Valueof (obj)); } return result.toString (); }}Die obige Druckwerkzeugklasse bietet einige praktische statische Methoden für die Ausgabe und bietet einige überlastete Versionen. Sie können einige überlastete Versionen basierend auf Ihren persönlichen Vorlieben schreiben und den Druck grundlegender Arten eindimensionaler Arrays und mehrdimensionaler Arrays unterstützen. Siehe die folgenden Beispiele des Druckwerkzeugtests:
Paket cn.zq.array.reflect; Import statischer cn.zq.util.print.print; importieren java.io.printstream; statische cn.zq.util.print.*; public class Printtest {statische Klasse Person {private statische Int -Zähler; private endgültige int id = counter ++; public String toString () {return getClass (). GetImleName () + id; }} public static void main (String [] args) löst eine Ausnahme aus {print ("-drucken nicht array-"); print (neues Objekt ()); print ("-eindimensionale Array von Grundtypen drucken-"); int [] ist = new int [] {1, 22, 31, 44, 21, 33, 65}; Druck (IS); print ("-zweidimensionale Array von Grundtypen drucken-"); int [] [] iss = new int [] [] {{{{11, 12, 13, 14}, {21, 22,}, {31, 32, 33}}; Print (ISS); print ("-eindimensionales Array von Nicht-Basistypen drucken-"); Person [] Personen = neue Person [10]; für (int i = 0; i <personons.length; i ++) {persons [i] = new Person (); } print (Personen); Druck (Personen); print ("-Drucken Sie ein zweidimensionales Array von nichtprimitiven Typen-"); Person [] [] [] persons2 = new Person [] [] [] {{new Person ()}, {new Person (), new Person ()}, {new Person (), New Person (), New Person (), New Person (),},}; print (persons2); print ("-ein leeres Array drucken-"); print (new int [] {}); print ("-Drucken Sie ein Array mit Nullwerten-"); Object [] Objects = New Object [] {new Person (), null, new Object (), New Integer (100)}; print (Objekte); print ("-zweidimensionales Array für Sonderfälle drucken-"); Object [] [] Objekte2 = neues Objekt [3] []; Objects2 [0] = neues Objekt [] {}; Objekte2 [2] = Objekte; print (Objekte2); print ("-das Ergebnis des eindimensionalen Arrays in die Datei ausgeben-"); Printstream out = new printStream ("out.c"); Versuchen Sie {print (iss, out); } endlich {out.close (); } print ("-Formatausgabe--"); Format (" %-6d %s %b %s", 10086, ",", true, ISS); /** * Einige häufig verwendete Methoden von Druckwerkzeugklassen sind oben aufgeführt. * Es gibt auch einige nicht gelistete Methoden. Überprüfen Sie es bitte selbst. */}} Ausgabe:
--Print non-array -- java.lang.Object@61de33 --Print one-dimensional array of basic types -- [1, 22, 31, 44, 21, 33, 65] --Print two-dimensional array of basic types -- [[11, 12, 13, 14], [21, 22], [31, 32, 33]] --Print one-dimensional array of non-base type -- [Person0, Person1, Person2, Person3, Person4, Person5, Person6, Person7, Person8, Person9] --Print two-dimensional array of non-base type -- [[Person10], [Person11, Person12], [Person13, Person14, Person15]] --Print empty array -- [] --Print array with null values -- [Person16, null, java.lang.Object@ca0b6, 100] --Print two-dimensional array in special cases -- [[], null, [Person16, null, java.lang.Object@ca0b6, 100]] --Print the result of the one-dimensional array to a file -- - Format output -- 10086 is TRUE [[11, 12, 13, 14], [21, 22], [31, 32, 33]]
Ausgabedatei:
Es ist ersichtlich, dass die Druckwerkzeugklasse bereits in der Lage ist, grundlegende Arten von eindimensionalen Arrays und mehrdimensionalen Arrays zu drucken. Im Allgemeinen ist die obige Werkzeugklasse sehr praktisch, um nicht jedes Mal, wenn Sie den Inhalt im Array sehen möchten, manuell Code zu schreiben. Das wäre zu problematisch. Verwenden Sie einfach die Druckwerkzeugklasse in der Zukunft. Wie bequem.
Die obige Werkzeugklasse funktioniert sehr gut, aber wenn es eine Anforderung gibt: Geben Sie Ihnen ein Array (und möglicherweise andere Container), Sie können eine Liste für mich erstellen. Also, was sollen wir tun? Tatsächlich erhält Arrays.aSlist nicht immer die erwarteten Ergebnisse. Obwohl Java5 Generika hinzufügt, hat es Einschränkungen und kann nicht so allgemein wie C ++ - Vorlagen sein. Genau deshalb gibt es Grundtypen in Java. Auch wenn es einen automatischen Verpackungsmechanismus gibt, kann er nicht mit Generika verwendet werden. Der Parametertyp muss von einem bestimmten Typ und kein Grundtyp sein. Hier ist eine eigene Lösung:
Paket cn.zq.util; Import Java.lang.reflect.Array; Import Java.util.ArrayList; Import Java.util.Arrays; Import Java.util.Enumeration; Import Java.util.iterator; importieren java.util.list; import Java.util.map; public class collectionutils {public static list <?> ASList (Objekt obj) {return convertTolist (makesiderator (obj)); } public static <T> List <T> convertTolist (Iterator <T> Iterator) {if (iterator == null) {return null; } List <T> list = new ArrayList <T> (); while (iterator.hasnext ()) {list.add (iterator.next ()); } Rückgabeliste; } @Suppresswarnings ({"rawtypes", "Deaktiviert"}) public static iterator <?> MakeIterator (Objekt obj) {if (obj instanceof iterator) {return (iterator <>) obj; } if (obj == null) {return null; } if (obj instanceof map) {obj = ((map <?,?>) obj) .EntrySet (); } Iterator <?> Iterator = null; if (obj instanceof iterable) {iterator = ((iterable <?>) obj) .Iterator (); } else if (obj.getClass (). isArray ()) {// Object [] objs = (Object []) obj; // oder Arrays von primitiven Typen können nicht wie diese ArrayList -Liste = new ArrayList (array.getLength (obj)) konvertiert werden; für (int i = 0; i <array.getLength (obj); i ++) {list.add (array.get (obj, i)); } iterator = list.iterator (); } else if (obj Instanceof Enumeration) {iterator = new EnumerationIterator ((Enumeration) obj); } else {iterator = arrays.aslist (obj) .Iterator (); } Return Iterator; } öffentliche statische Klasse EnumerationIterator <T> implementiert Iterator <T> {private Enumeration <T> Enumeration; public enumerationIterator (Enumeration <T> Aufzählung) {this.Enumeration = Enumeration; } public boolean hasNext () {return enumeration.hasmoreElements (); } public t Next () {return enumeration.nextElement (); } public void remove () {neue nicht unterstützte OperationException (); }}}Testcode:
Paket cn.zq.array.reflect; Import Java.util.iterator; importieren java.util.list; import cn.zq.array.reflect.printtest.person; import cn.zq.util.collectionutils; public class CollectionItilstest {public static void main (String [] args) {System.out.println ("--- Grundtyp eindimensionales Array-"); int [] nums = {1, 3, 5, 7, 9}; Liste <?> List = collectionUtils.aSlist (nums); System.out.println (Liste); System.out.println ("-nicht grundlegend ein eindimensionales Array vom Typ Typ-"); Person [] persons = new Person [] {New Person (), New Person (), New Person (),}; Liste <Person> personList = (list <Person>) collectionUtils.aslist (Personen); System.out.println (Personlist); System.out.println (Personlist); System.out.println ("-Iterator--"); Iterator <Person> iterator = personList.Iterator (); Liste <Person> Personlist2 = (Liste <Person>) collectionUtils.aslist (Iterator); System.out.println (Personlist2); }}Ausgabe:
-Basic Typ One-Dimensional Array-[1, 3, 5, 7, 9]-Non-Basic Typ One-Dimensional Array-[Person0, Person1, Person2]-Kiterator-[Person0, Person1, Person2]
In der Bibliothek der Java -Containerklasse kann sie in Sammlung, Karte und Array unterteilt werden. Da die Iterator (und die frühe Legacy -Schnittstelle) die allgemeine Schnittstelle aller Container ist und die Sammlungsschnittstelle von iterierbar ist (der Iterator dieser Schnittstelle gibt einen Iterator zurück), werden diese Situationen nacheinander in der Makiterator -Methode verarbeitet. Für Kartentypen muss nur die Einstiegsmethode () aufgerufen werden. Rufen Sie für Klassen, die die iterable Schnittstelle (einschließlich Sammlung) implementieren, Iterator () auf, um das Iteratorobjekt direkt zu erhalten. Verwenden Sie für Aufzählungstypen den Adapter EnumerationIterator zur Anpassung. Verwenden Sie für Arrays die Array -Reflexion, um das Array in ArrayList zu durchqueren, und rufen Sie die Methode Arrays.aslist () auf, um eine Liste für andere Typen zu erstellen. CollectionUtils bietet auch einige andere Methoden zum Konvertieren. Sie können die nach Bedarf benötigten Methoden hinzufügen.
Zusammenfassung: Array -Reflexion bietet bequemere und flexiblere Methoden für Designs, bei denen Arrays erscheinen können, um keine störender Beurteilungsaussagen zu schreiben. Diese Flexibilität zahlt den Leistungspreis und es ist wirklich nicht erforderlich, Array -Reflexion zu verwenden, wenn Array -Reflexion überhaupt nicht benötigt wird. Die Verwendung von Array -Reflexionen unterscheidet sich in der tatsächlichen Entwicklung. Wählen Sie, ob Sie Array -Reflexionen entsprechend den Bedürfnissen verwenden. Der beste Weg ist es, den Weg durch das Üben zu erforschen, so zu schreiben, wie Sie es denken und sich in der Praxis ständig verbessern.