Was ist Reflexion und warum ist sie nützlich?

2124

Was ist Reflexion und warum ist sie nützlich?

Ich interessiere mich besonders für Java, aber ich gehe davon aus, dass die Prinzipien in jeder Sprache gleich sind.

Lehane
quelle
9
Für mich ist es eine Möglichkeit, Klassennamen zur Laufzeit abzurufen und Objekte dieser Klasse zu erstellen.
Nabin
64
Da dies eine beliebte Frage ist, möchte ich darauf hinweisen, dass Reflexion (ohne Anmerkungen) das allerletzte Werkzeug sein sollte, zu dem Sie bei der Lösung eines Problems gehen. Ich benutze es und liebe es, aber es hebt alle Vorteile der statischen Typisierung von Java auf. Wenn Sie es brauchen, isolieren Sie es auf einen möglichst kleinen Bereich (eine Methode oder eine Klasse). Es ist akzeptabler, es in Tests zu verwenden als Produktionscode. Mit Anmerkungen sollte es in Ordnung sein - Der Hauptpunkt besteht darin, Klassen- oder Methodennamen nicht als "Strings" anzugeben, wenn Sie dies möglicherweise vermeiden können.
Bill K
4
Zusätzlich zu @ BillKs Kommentar: Reflexion ist sehr mächtig, ich würde es Magie nennen. Mit großer Macht kommt große Verantwortung. Verwenden Sie es nur, wenn Sie wissen, was Sie tun.
MC Emperor
Mit Manifold können Sie viele der mit der Reflexion verbundenen Fallstricke vermeiden @Jailbreak. Es bietet direkten, typsicheren Zugriff auf private Felder, Methoden usw. Lassen Sie den Java-Compiler Ihren Code sicher überprüfen und Manifold den zugrunde liegenden Reflection-Zugriff für Sie generieren. Weitere Informationen: manifold.systems/docs.html#type-safe-reflection
Scott

Antworten:

1716

Die Namensreflexion wird verwendet, um Code zu beschreiben, der anderen Code im selben System (oder selbst) überprüfen kann.

Angenommen, Sie haben ein Objekt eines unbekannten Typs in Java und möchten eine 'doSomething'-Methode aufrufen, falls eine vorhanden ist. Das statische Typisierungssystem von Java ist nicht wirklich darauf ausgelegt, dies zu unterstützen, es sei denn, das Objekt entspricht einer bekannten Schnittstelle. Mithilfe von Reflection kann Ihr Code das Objekt jedoch überprüfen und herausfinden, ob es eine Methode namens "doSomething" enthält, und es dann aufrufen, wenn Sie dies tun möchte.

Um Ihnen ein Codebeispiel dafür in Java zu geben (stellen Sie sich vor, das betreffende Objekt ist foo):

Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);

Ein sehr häufiger Anwendungsfall in Java ist die Verwendung mit Anmerkungen. JUnit 4 verwendet beispielsweise Reflection, um Ihre Klassen nach Methoden zu durchsuchen, die mit der Annotation @Test gekennzeichnet sind, und ruft sie dann beim Ausführen des Komponententests auf.

Unter http://docs.oracle.com/javase/tutorial/reflect/index.html finden Sie einige gute Beispiele für Überlegungen

Und schließlich, ja, sind die Konzepte in anderen statisch typisierten Sprachen, die die Reflexion unterstützen (wie C #), ziemlich ähnlich. In dynamisch typisierten Sprachen ist der oben beschriebene Anwendungsfall weniger erforderlich (da der Compiler zulässt, dass eine Methode für ein Objekt aufgerufen wird und zur Laufzeit fehlschlägt, wenn sie nicht vorhanden ist), aber der zweite Fall, nach Methoden zu suchen, die mit oder markiert sind Arbeit auf eine bestimmte Art und Weise ist immer noch üblich.

Update von einem Kommentar:

Die Möglichkeit, den Code im System zu überprüfen und Objekttypen anzuzeigen, ist keine Reflexion, sondern eine Typinspektion. Reflexion ist dann die Fähigkeit, zur Laufzeit Änderungen vorzunehmen, indem Introspektion verwendet wird. Die Unterscheidung ist hier notwendig, da einige Sprachen Introspektion unterstützen, aber keine Reflexion unterstützen. Ein solches Beispiel ist C ++

Matt Sheppard
quelle
32
Kannst du bitte erklären, welche Bedeutung dieser Null-Parameter in dieser Zeile hat? Method method = foo.getClass (). getMethod ("doSomething", null);
Krsna Chaitanya
54
Die Null gibt an, dass keine Parameter an die foo-Methode übergeben werden. Weitere Informationen finden Sie unter docs.oracle.com/javase/6/docs/api/java/lang/reflect/… , java.lang.Object ...).
Matt Sheppard
791
Nur um aufzuklären, da dies so viele positive Stimmen hat. Die Möglichkeit, den Code im System zu überprüfen und Objekttypen anzuzeigen, ist keine Reflexion, sondern eine Typinspektion. Reflexion ist dann die Fähigkeit, zur Laufzeit Änderungen vorzunehmen, indem Introspektion verwendet wird. Die Unterscheidung ist hier notwendig, da einige Sprachen Introspektion unterstützen, aber keine Reflexion unterstützen. Ein solches Beispiel ist C ++.
Bigtunacan
39
Ich liebe Reflexion, aber wenn Sie die Kontrolle über den Code haben, ist die Verwendung der in dieser Antwort angegebenen Reflexion unnötig und daher ein Missbrauch. Sie sollten Type Introspection (instanceof) und starke Typen verwenden. Wenn es nur eine Reflexion gibt, um etwas zu tun, sollte es so gemacht werden. Reflexion verursacht ernsthafte Herzschmerzen, da Sie alle Vorteile einer statisch typisierten Sprache verlieren. Wenn Sie es brauchen, brauchen Sie es, aber selbst dann würde ich eine vorgefertigte Lösung wie Spring oder etwas in Betracht ziehen, das die notwendige Reflexion vollständig einschließt - IE: Lassen Sie jemand anderen die Kopfschmerzen haben.
Bill K
6
@bigtunacan Woher hast du diese Informationen? Ich sehe den Begriff "Reflektion" in der offiziellen Java-Dokumentation von Oracle, der nicht nur die Fähigkeit beschreibt, Änderungen zur Laufzeit vorzunehmen, sondern auch die Fähigkeit, den Typ eines Objekts zu sehen. Ganz zu schweigen davon, dass die meisten so genannte „Typ Innerlichkeit“ verwandte Klassen (zB: Method, Constructor, Modifier, Field, Member, im Grunde scheinbar alle außer Class) sind im java.lang.*reflect*Paket. Vielleicht umfasst das Konzept "Reflexion" sowohl "Typ-Introspektion" als auch Modifikation zur Laufzeit umfassend?
RestInPeace
246

Reflexion ist die Fähigkeit einer Sprache, Klassen, Methoden, Attribute usw. zur Laufzeit zu überprüfen und dynamisch aufzurufen.

Beispielsweise verfügen alle Objekte in Java über die Methode getClass(), mit der Sie die Klasse des Objekts bestimmen können, auch wenn Sie sie zur Kompilierungszeit nicht kennen (z. B. wenn Sie sie als deklariert haben Object). Dies mag trivial erscheinen, eine solche Reflexion ist jedoch nicht möglich in weniger dynamischen Sprachen wieC++ . Mit erweiterten Anwendungen können Sie Methoden, Konstruktoren usw. auflisten und aufrufen.

Reflexion ist wichtig, da Sie damit Programme schreiben können, die zur Kompilierungszeit nicht alles "wissen" müssen, wodurch sie dynamischer werden, da sie zur Laufzeit miteinander verknüpft werden können. Der Code kann gegen bekannte Schnittstellen geschrieben werden, aber die tatsächlich zu verwendenden Klassen können mithilfe der Reflektion aus Konfigurationsdateien instanziiert werden.

Viele moderne Frameworks verwenden aus diesem Grund häufig Reflexion. Die meisten anderen modernen Sprachen verwenden ebenfalls Reflektion und sind in Skriptsprachen (wie Python) noch enger integriert, da sie sich im allgemeinen Programmiermodell dieser Sprachen natürlicher anfühlen.

Liedman
quelle
2
Mit anderen Worten, Sie können eine Instanz aus ihrem qualifizierten Namen erstellen, und der Compiler wird sich nicht darüber beschweren (weil Sie nur einen String für den Klassennamen verwenden). Wenn diese Klasse zur Laufzeit nicht vorhanden ist, erhalten Sie eine Ausnahme. Sie haben den Compiler in diesem Fall irgendwie umgangen. Würden Sie mir einen speziellen Anwendungsfall dafür geben? Ich kann mir einfach nicht vorstellen, wann ich es wählen würde.
Fernando Gabrieli
3
@FernandoGabrieli Es ist zwar richtig, dass es einfach ist, Laufzeitfehler mit Reflection zu erstellen, aber es ist auch durchaus möglich, Reflection zu verwenden, ohne Laufzeitausnahmen zu riskieren. Wie in meiner Antwort angedeutet, werden Reflexionen häufig für Bibliotheken oder Frameworks verwendet, die die Struktur der Anwendung zur Kompilierungszeit explizit nicht kennen, da sie getrennt von der Anwendung kompiliert werden. Jede Bibliothek, die "Code by Convention" verwendet, verwendet wahrscheinlich Reflektion, jedoch nicht unbedingt magische Zeichenfolgen.
Liedman
C++enthält Informationen zum Laufzeit-Typ. RTTI
Ayxan
114

Eine meiner Lieblingsanwendungen der Reflexion ist die folgende Java-Dump-Methode. Es nimmt jedes Objekt als Parameter und verwendet die Java Reflection API, um jeden Feldnamen und Wert auszudrucken.

import java.lang.reflect.Array;
import java.lang.reflect.Field;

public static String dump(Object o, int callCount) {
    callCount++;
    StringBuffer tabs = new StringBuffer();
    for (int k = 0; k < callCount; k++) {
        tabs.append("\t");
    }
    StringBuffer buffer = new StringBuffer();
    Class oClass = o.getClass();
    if (oClass.isArray()) {
        buffer.append("\n");
        buffer.append(tabs.toString());
        buffer.append("[");
        for (int i = 0; i < Array.getLength(o); i++) {
            if (i < 0)
                buffer.append(",");
            Object value = Array.get(o, i);
            if (value.getClass().isPrimitive() ||
                    value.getClass() == java.lang.Long.class ||
                    value.getClass() == java.lang.String.class ||
                    value.getClass() == java.lang.Integer.class ||
                    value.getClass() == java.lang.Boolean.class
                    ) {
                buffer.append(value);
            } else {
                buffer.append(dump(value, callCount));
            }
        }
        buffer.append(tabs.toString());
        buffer.append("]\n");
    } else {
        buffer.append("\n");
        buffer.append(tabs.toString());
        buffer.append("{\n");
        while (oClass != null) {
            Field[] fields = oClass.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                buffer.append(tabs.toString());
                fields[i].setAccessible(true);
                buffer.append(fields[i].getName());
                buffer.append("=");
                try {
                    Object value = fields[i].get(o);
                    if (value != null) {
                        if (value.getClass().isPrimitive() ||
                                value.getClass() == java.lang.Long.class ||
                                value.getClass() == java.lang.String.class ||
                                value.getClass() == java.lang.Integer.class ||
                                value.getClass() == java.lang.Boolean.class
                                ) {
                            buffer.append(value);
                        } else {
                            buffer.append(dump(value, callCount));
                        }
                    }
                } catch (IllegalAccessException e) {
                    buffer.append(e.getMessage());
                }
                buffer.append("\n");
            }
            oClass = oClass.getSuperclass();
        }
        buffer.append(tabs.toString());
        buffer.append("}\n");
    }
    return buffer.toString();
}
Ben Williams
quelle
8
Auf was sollte Callcount eingestellt werden?
Tom
8
Ich habe eine Ausnahme im Thread "AWT-EventQueue-0" java.lang.StackOverflowError erhalten, als ich dies ausgeführt habe.
Tom
3
@ Tom callCountsollte auf Null gesetzt werden. Der Wert wird verwendet, um zu bestimmen, wie viele Registerkarten vor jeder Ausgabezeile stehen sollen: Jedes Mal, wenn ein Dump ein "Unterobjekt" ausgeben muss, wird die Ausgabe als im übergeordneten Element verschachtelt gedruckt. Diese Methode erweist sich als nützlich, wenn sie in eine andere eingewickelt wird. Überlegen Sie printDump(Object obj){ System.out.println(dump(obj, 0)); }.
fny
1
Der java.lang.StackOverflowError kann bei Zirkelverweisen aufgrund der nicht aktivierten Rekursion erstellt werden: buffer.append (dump (value, callCount))
Arnaud P
4
Können Sie Ihren Code bitte speziell für Public Domain freigeben?
Stolsvik
84

Verwendung der Reflexion

Reflection wird häufig von Programmen verwendet, die die Fähigkeit benötigen, das Laufzeitverhalten von Anwendungen zu untersuchen oder zu ändern, die auf der virtuellen Java-Maschine ausgeführt werden. Dies ist eine relativ fortgeschrittene Funktion und sollte nur von Entwicklern verwendet werden, die die Grundlagen der Sprache gut verstehen. In Anbetracht dieser Einschränkung ist die Reflexion eine leistungsstarke Technik und kann es Anwendungen ermöglichen, Operationen auszuführen, die sonst unmöglich wären.

Erweiterungsfunktionen

Eine Anwendung kann externe, benutzerdefinierte Klassen verwenden, indem Instanzen von Erweiterungsobjekten unter Verwendung ihrer vollständig qualifizierten Namen erstellt werden. Klassenbrowser und visuelle Entwicklungsumgebungen Ein Klassenbrowser muss in der Lage sein, die Mitglieder von Klassen aufzulisten. Visuelle Entwicklungsumgebungen können von der Verwendung von Typinformationen profitieren, die in Reflection verfügbar sind, um dem Entwickler das Schreiben von korrektem Code zu erleichtern. Debugger und Testtools Debugger müssen in der Lage sein, private Mitglieder in Klassen zu untersuchen. Test-Harnesses können mithilfe von Reflection systematisch auffindbare Set-APIs aufrufen, die für eine Klasse definiert sind, um eine hohe Codeabdeckung in einer Testsuite sicherzustellen.

Nachteile der Reflexion

Reflexion ist stark, sollte aber nicht wahllos verwendet werden. Wenn es möglich ist, eine Operation ohne Reflexion durchzuführen, ist es vorzuziehen, sie nicht zu verwenden. Die folgenden Bedenken sollten beim Zugriff auf Code über Reflection berücksichtigt werden.

  • Leistungsaufwand

Da es sich bei der Reflektion um Typen handelt, die dynamisch aufgelöst werden, können bestimmte Optimierungen der Java Virtual Machine nicht durchgeführt werden. Folglich haben reflektierende Operationen eine langsamere Leistung als ihre nicht reflektierenden Gegenstücke und sollten in Codeabschnitten vermieden werden, die in leistungsempfindlichen Anwendungen häufig aufgerufen werden.

  • Sicherheitsbeschränkungen

Für die Reflexion ist eine Laufzeitberechtigung erforderlich, die möglicherweise nicht vorhanden ist, wenn sie unter einem Sicherheitsmanager ausgeführt wird. Dies ist eine wichtige Überlegung für Code, der in einem eingeschränkten Sicherheitskontext ausgeführt werden muss, z. B. in einem Applet.

  • Belichtung von Interna

Da durch Reflexion Code Vorgänge ausführen kann, die in nicht reflektierendem Code unzulässig sind, z. B. der Zugriff auf private Felder und Methoden, kann die Verwendung von Reflexion zu unerwarteten Nebenwirkungen führen, die den Code möglicherweise funktionsunfähig machen und die Portabilität zerstören. Reflektierender Code unterbricht Abstraktionen und kann daher das Verhalten bei Upgrades der Plattform ändern.

Quelle: Die Reflection-API

Desmond Smith
quelle
44

Reflexion ist ein Schlüsselmechanismus, mit dem eine Anwendung oder ein Framework mit Code arbeiten kann, der möglicherweise noch nicht einmal geschrieben wurde!

Nehmen Sie zum Beispiel Ihre typische web.xml-Datei. Dies enthält eine Liste von Servlet-Elementen, die verschachtelte Servlet-Klassenelemente enthalten. Der Servlet-Container verarbeitet die Datei web.xml und erstellt durch Reflektion eine neue Instanz jeder Servlet-Klasse.

Ein weiteres Beispiel wäre die Java-API für XML-Parsing (JAXP) . Wenn ein XML-Parser-Anbieter über bekannte Systemeigenschaften 'eingesteckt' wird, die zum Erstellen neuer Instanzen durch Reflektion verwendet werden.

Und schließlich ist das umfassendste Beispiel Spring , das Reflexion verwendet, um seine Bohnen zu erstellen, und für die starke Verwendung von Proxys

Toolkit
quelle
36

Nicht jede Sprache unterstützt die Reflexion, aber die Prinzipien sind in den Sprachen, die sie unterstützen, normalerweise dieselben.

Reflexion ist die Fähigkeit, die Struktur Ihres Programms zu "reflektieren". Oder konkreter. Um die vorhandenen Objekte und Klassen zu betrachten und programmgesteuert Informationen zu den von ihnen implementierten Methoden, Feldern und Schnittstellen zurückzugewinnen. Sie können sich auch Dinge wie Anmerkungen ansehen.

Es ist in vielen Situationen nützlich. Überall, wo Sie Klassen dynamisch in Ihren Code einbinden möchten. Viele objektrelationale Mapper verwenden Reflektion, um Objekte aus Datenbanken instanziieren zu können, ohne vorher zu wissen, welche Objekte sie verwenden werden. Plug-in-Architekturen sind ein weiterer Ort, an dem Reflexion nützlich ist. In solchen Situationen ist es wichtig, Code dynamisch laden und feststellen zu können, ob es Typen gibt, die die richtige Schnittstelle für die Verwendung als Plugin implementieren.

Mendelt
quelle
Ich muss Objekte basierend auf den in der DB vorhandenen Daten instanziieren. Ich glaube, das ist es, worüber Sie sagen. Beispielcode würde mir sehr helfen. Danke im Voraus.
Atom
34

Die Reflexion ermöglicht die Instanziierung neuer Objekte, den Aufruf von Methoden und das dynamische Abrufen / Festlegen von Operationen für Klassenvariablen zur Laufzeit, ohne dass zuvor Kenntnisse über deren Implementierung vorliegen.

Class myObjectClass = MyObject.class;
Method[] method = myObjectClass.getMethods();

//Here the method takes a string parameter if there is no param, put null.
Method method = aClass.getMethod("method_name", String.class); 

Object returnValue = method.invoke(null, "parameter-value1");

Im obigen Beispiel ist der Parameter null das Objekt, für das Sie die Methode aufrufen möchten. Wenn die Methode statisch ist, geben Sie null an. Wenn die Methode nicht statisch ist, müssen Sie beim Aufrufen eine gültige MyObject-Instanz anstelle von null angeben.

Mit Reflection können Sie auch auf private Mitglieder / Methoden einer Klasse zugreifen:

public class A{

  private String str= null;

  public A(String str) {
  this.str= str;
  }
}

.

A obj= new A("Some value");

Field privateStringField = A.class.getDeclaredField("privateString");

//Turn off access check for this field
privateStringField.setAccessible(true);

String fieldValue = (String) privateStringField.get(obj);
System.out.println("fieldValue = " + fieldValue);
  • Für die Überprüfung von Klassen (auch als Selbstbeobachtung bezeichnet) müssen Sie das Reflection-Paket ( java.lang.reflect) nicht importieren . Auf Klassenmetadaten kann über zugegriffen werden java.lang.Class.

Reflection ist eine sehr leistungsfähige API, kann jedoch die Anwendung verlangsamen, wenn sie übermäßig verwendet wird, da alle Typen zur Laufzeit aufgelöst werden.

Nikhil Shekhar
quelle
21

Java Reflection ist sehr leistungsfähig und kann sehr nützlich sein. Java Reflection macht es möglich Klassen, Schnittstellen, Felder und Methoden zur Laufzeit überprüft werden, ohne die Namen der Klassen, Methoden usw. zur Kompilierungszeit zu kennen. Es ist auch möglich, neue Objekte zu instanziieren, Methoden aufzurufen und Feldwerte mithilfe von Reflektion abzurufen / festzulegen.

Ein kurzes Java Reflection-Beispiel zeigt Ihnen, wie die Verwendung von Reflection aussieht:

Method[] methods = MyObject.class.getMethods();

    for(Method method : methods){
        System.out.println("method = " + method.getName());
    }

In diesem Beispiel wird das Class-Objekt aus der Klasse MyObject abgerufen. Mit dem Klassenobjekt erhält das Beispiel eine Liste der Methoden in dieser Klasse, iteriert die Methoden und druckt ihre Namen aus.

Wie das alles genau funktioniert, wird hier erklärt

Bearbeiten : Nach fast 1 Jahr bearbeite ich diese Antwort, da ich beim Lesen über Reflexion nur noch wenige Anwendungen von Reflexion habe.

  • Spring verwendet eine Bean-Konfiguration wie:


<bean id="someID" class="com.example.Foo">
    <property name="someField" value="someValue" />
</bean>

Wenn der Spring-Kontext dieses <Bean> -Element verarbeitet, verwendet er Class.forName (String) mit dem Argument "com.example.Foo", um diese Klasse zu instanziieren.

Anschließend wird die Reflektion erneut verwendet, um den entsprechenden Setter für das <Eigenschaft> -Element abzurufen und seinen Wert auf den angegebenen Wert zu setzen.

  • Junit verwendet Reflection speziell zum Testen von privaten / geschützten Methoden.

Für private Methoden

Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

Für private Felder,

Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
VdeX
quelle
21

Beispiel:

Nehmen Sie zum Beispiel eine Remote-Anwendung, die Ihrer Anwendung ein Objekt gibt, das Sie mithilfe ihrer API-Methoden erhalten. Basierend auf dem Objekt müssen Sie möglicherweise eine Berechnung durchführen.

Der Anbieter garantiert, dass das Objekt drei Typen haben kann und wir eine Berechnung basierend auf dem Objekttyp durchführen müssen.

Daher können wir in 3 Klassen implementieren, die jeweils eine andere Logik enthalten. Offensichtlich sind die Objektinformationen zur Laufzeit verfügbar, sodass Sie für die Berechnung keinen statischen Code erstellen können. Daher wird die Reflexion verwendet, um das Objekt der Klasse zu instanziieren, das Sie zur Durchführung der Berechnung auf der Grundlage der Objekt vom Anbieter erhalten.

human.js
quelle
Ich brauche etwas Ähnliches. Ein Beispiel würde mir sehr helfen, da ich neu in Reflexionskonzepten bin.
Atom
2
Ich bin verwirrt: Können Sie instanceofden Objekttyp nicht zur Laufzeit bestimmen?
ndm13
19

Einfaches Beispiel für Reflexion. In einem Schachspiel wissen Sie nicht, was der Benutzer zur Laufzeit bewegt. Mit Reflection können Methoden aufgerufen werden, die bereits zur Laufzeit implementiert sind:

public class Test {

    public void firstMoveChoice(){
        System.out.println("First Move");
    } 
    public void secondMOveChoice(){
        System.out.println("Second Move");
    }
    public void thirdMoveChoice(){
        System.out.println("Third Move");
    }

    public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 
        Test test = new Test();
        Method[] method = test.getClass().getMethods();
        //firstMoveChoice
        method[0].invoke(test, null);
        //secondMoveChoice
        method[1].invoke(test, null);
        //thirdMoveChoice
        method[2].invoke(test, null);
    }

}
Isuru Jayakantha
quelle
18

Reflection ist eine API, mit der das Verhalten von Methoden, Klassen und Schnittstellen zur Laufzeit untersucht oder geändert wird .

  1. Die erforderlichen Reflexionsklassen finden Sie unter java.lang.reflect package.
  2. Die Reflexion gibt uns Informationen über die Klasse, zu der ein Objekt gehört, sowie über die Methoden dieser Klasse, die mit dem Objekt ausgeführt werden können.
  3. Durch Reflexion können wir zur Laufzeit Methoden aufrufen, unabhängig davon, welcher Zugriffsspezifizierer mit ihnen verwendet wird.

Die Pakete java.langund java.lang.reflectbieten Klassen für die Java-Reflexion.

Reflexion kann verwendet werden, um Informationen über - zu erhalten

  1. Klasse Die getClass()Methode wird verwendet, um den Namen der Klasse abzurufen, zu der ein Objekt gehört.

  2. Konstruktoren Mit dieser getConstructors()Methode werden die öffentlichen Konstruktoren der Klasse abgerufen, zu der ein Objekt gehört.

  3. Methoden Die getMethods()Methode wird verwendet, um die öffentlichen Methoden der Klasse abzurufen, zu der ein Objekt gehört.

Die Reflection-API wird hauptsächlich verwendet in:

IDE (Integrated Development Environment), z. B. Eclipse, MyEclipse, NetBeans usw.
Debugger- und Testtools usw.

Vorteile der Verwendung von Reflexion:

Erweiterungsfunktionen: Eine Anwendung kann externe, benutzerdefinierte Klassen verwenden, indem Instanzen von Erweiterungsobjekten unter Verwendung ihrer vollständig qualifizierten Namen erstellt werden.

Debugging- und Testtools: Debugger verwenden die Eigenschaft der Reflektion, um private Mitglieder in Klassen zu untersuchen.

Nachteile:

Leistungsaufwand: Reflektierende Vorgänge weisen eine langsamere Leistung auf als nicht reflektierende Vorgänge und sollten in Codeabschnitten vermieden werden, die in leistungsempfindlichen Anwendungen häufig aufgerufen werden.

Belichtung von Interna: Reflektierender Code unterbricht Abstraktionen und kann daher das Verhalten bei Upgrades der Plattform ändern.

Ref: Java Reflection javarevisited.blogspot.in

Roottraveller
quelle
4
Ich würde zu den Nachteilen " Es bricht Refactoring " hinzufügen . Für mich ist das der Hauptgrund, Reflexionen so weit wie möglich zu vermeiden.
SantiBailors
So können wir (zum Beispiel) die Klassen überprüfen, die wir haben (ob wir Instanzen davon haben oder nicht), richtig? Damit meine ich, holen Sie sich ihre Methoden oder Konstruktoren und verwenden Sie sie, um neue Instanzen zu erstellen / sie aufzurufen. Warum sagen wir "Programmverhalten ändern", wenn das Verhalten bereits vorhanden ist, aber einen anderen Code hat? Warum heißt es "Reflexion"? Danke
Fernando Gabrieli
15

Nach meinem Verständnis:

Durch Reflexion kann der Programmierer dynamisch auf Entitäten im Programm zugreifen. Wenn der Programmierer beim Codieren einer Anwendung keine Kenntnis von einer Klasse oder ihren Methoden hat, kann er diese Klasse dynamisch (zur Laufzeit) mithilfe von Reflection verwenden.

Es wird häufig in Szenarien verwendet, in denen sich ein Klassenname häufig ändert. Wenn eine solche Situation auftritt, ist es für den Programmierer kompliziert, die Anwendung neu zu schreiben und den Namen der Klasse immer wieder zu ändern.

Stattdessen muss durch die Verwendung von Reflection über einen sich möglicherweise ändernden Klassennamen nachgedacht werden.

Pramod
quelle
15

Reflection ist eine Reihe von Funktionen, mit denen Sie auf die Laufzeitinformationen Ihres Programms zugreifen und dessen Verhalten ändern können (mit einigen Einschränkungen).

Dies ist nützlich, da Sie damit das Laufzeitverhalten in Abhängigkeit von den Metainformationen Ihres Programms ändern können. Sie können also den Rückgabetyp einer Funktion überprüfen und die Art und Weise ändern, wie Sie mit der Situation umgehen.

In C # können Sie beispielsweise eine Assembly (eine DLL) zur Laufzeit laden und untersuchen, durch die Klassen navigieren und die entsprechenden Aktionen ausführen. Außerdem können Sie zur Laufzeit eine Instanz einer Klasse erstellen, ihre Methode aufrufen usw.

Wo kann es nützlich sein? Ist nicht jedes Mal nützlich, aber für konkrete Situationen. Sie können es beispielsweise verwenden, um den Namen der Klasse für Protokollierungszwecke abzurufen, Handler für Ereignisse dynamisch gemäß den Angaben in einer Konfigurationsdatei zu erstellen usw.

Jorge Córdoba
quelle
11

Ich möchte nur einen Punkt zu allem hinzufügen, was aufgelistet wurde.

Mit der Reflection-API können Sie eine universelle toString()Methode für jedes Objekt schreiben .

Es ist nützlich beim Debuggen.

Hier ist ein Beispiel:

class ObjectAnalyzer {

   private ArrayList<Object> visited = new ArrayList<Object>();

   /**
    * Converts an object to a string representation that lists all fields.
    * @param obj an object
    * @return a string with the object's class name and all field names and
    * values
    */
   public String toString(Object obj) {
      if (obj == null) return "null";
      if (visited.contains(obj)) return "...";
      visited.add(obj);
      Class cl = obj.getClass();
      if (cl == String.class) return (String) obj;
      if (cl.isArray()) {
         String r = cl.getComponentType() + "[]{";
         for (int i = 0; i < Array.getLength(obj); i++) {
            if (i > 0) r += ",";
            Object val = Array.get(obj, i);
            if (cl.getComponentType().isPrimitive()) r += val;
            else r += toString(val);
         }
         return r + "}";
      }

      String r = cl.getName();
      // inspect the fields of this class and all superclasses
      do {
         r += "[";
         Field[] fields = cl.getDeclaredFields();
         AccessibleObject.setAccessible(fields, true);
         // get the names and values of all fields
         for (Field f : fields) {
            if (!Modifier.isStatic(f.getModifiers())) {
               if (!r.endsWith("[")) r += ",";
               r += f.getName() + "=";
               try {
                  Class t = f.getType();
                  Object val = f.get(obj);
                  if (t.isPrimitive()) r += val;
                  else r += toString(val);
               } catch (Exception e) {
                  e.printStackTrace();
               }
            }
         }
         r += "]";
         cl = cl.getSuperclass();
      } while (cl != null);

      return r;
   }    
}
nazar_art
quelle
11

Reflexion besteht darin, das Objekt sein Aussehen sehen zu lassen. Dieses Argument scheint nichts mit Reflexion zu tun zu haben. In der Tat ist dies die Fähigkeit, sich selbst zu identifizieren.

Reflexion selbst ist ein Wort für solche Sprachen, denen die Fähigkeit zur Selbsterkenntnis und Selbsterkenntnis fehlt, wie Java und C #. Da sie nicht die Fähigkeit zur Selbsterkenntnis haben, müssen wir, wenn wir beobachten wollen, wie es aussieht, etwas anderes haben, um darüber nachzudenken, wie es aussieht. Hervorragende dynamische Sprachen wie Ruby und Python können die Reflexion ihrer eigenen Sprache ohne die Hilfe anderer Personen wahrnehmen. Wir können sagen, dass das Objekt von Java nicht erkennen kann, wie es ohne einen Spiegel aussieht, der ein Objekt der Reflexionsklasse ist, aber ein Objekt in Python kann es ohne einen Spiegel wahrnehmen. Deshalb brauchen wir Reflexion in Java.

Marcus Thornton
quelle
Typ (), isinstance (), callable (), dir () und getattr (). .... das sind pythonische Reflexionsaufrufe
AnthonyJClink
9

Von Java - Dokumentation Seite

java.lang.reflectDas Paket enthält Klassen und Schnittstellen zum Abrufen reflektierender Informationen zu Klassen und Objekten. Reflection ermöglicht den programmgesteuerten Zugriff auf Informationen zu Feldern, Methoden und Konstruktoren geladener Klassen sowie die Verwendung von reflektierten Feldern, Methoden und Konstruktoren, um ihre zugrunde liegenden Gegenstücke innerhalb von Sicherheitsbeschränkungen zu bearbeiten.

AccessibleObjectermöglicht die Unterdrückung von Zugriffsprüfungen, wenn die erforderlichen ReflectPermissionverfügbar sind.

Klassen in diesem Paket sowie java.lang.ClassAnwendungen wie Debugger, Interpreter, Objektinspektoren, Klassenbrowser und Dienste wie Object SerializationundJavaBeans , die Zugriff auf die öffentlichen Mitglieder eines Zielobjekts (basierend auf seiner Laufzeitklasse) oder die von deklarierten Mitglieder benötigen eine bestimmte Klasse

Es enthält folgende Funktionen.

  1. Klassenobjekte erhalten,
  2. Untersuchen der Eigenschaften einer Klasse (Felder, Methoden, Konstruktoren),
  3. Feldwerte einstellen und abrufen,
  4. Methoden aufrufen,
  5. Neue Instanzen von Objekten erstellen.

In diesem Dokumentationslink finden Sie Informationen zu den von der ClassKlasse bereitgestellten Methoden .

Aus diesem Artikel (von Dennis Sosnoski, Präsident von Sosnoski Software Solutions, Inc) und diesem Artikel (Sicherheitsuntersuchungen pdf):

Ich sehe erhebliche Nachteile als die Verwendung von Reflection

Benutzer der Reflexion:

  1. Es bietet eine sehr vielseitige Möglichkeit, Programmkomponenten dynamisch zu verknüpfen
  2. Es ist nützlich, um Bibliotheken zu erstellen, die auf sehr allgemeine Weise mit Objekten arbeiten

Nachteile der Reflexion:

  1. Die Reflexion ist viel langsamer als der direkte Code, wenn sie für den Feld- und Methodenzugriff verwendet wird.
  2. Es kann verdecken, was in Ihrem Code tatsächlich vor sich geht
  3. Es umgeht den Quellcode und kann zu Wartungsproblemen führen
  4. Der Reflexionscode ist auch komplexer als der entsprechende direkte Code
  5. Es ermöglicht die Verletzung wichtiger Java-Sicherheitsbeschränkungen wie Datenzugriffsschutz und Typensicherheit

Allgemeiner Missbrauch:

  1. Laden von eingeschränkten Klassen,
  2. Abrufen von Verweisen auf Konstruktoren, Methoden oder Felder einer eingeschränkten Klasse,
  3. Erstellen neuer Objektinstanzen, Aufrufen von Methoden, Abrufen oder Festlegen von Feldwerten einer eingeschränkten Klasse.

Schauen Sie sich diese SE-Frage zum Missbrauch der Reflexionsfunktion an:

Wie lese ich ein privates Feld in Java?

Zusammenfassung:

Unsichere Nutzung ihrer Funktionen innerhalb eines Systems Code durchgeführt kann auch führen leicht auf den Kompromiss eines Java - Sicherheitsmodus l. Verwenden Sie diese Funktion daher sparsam

Ravindra Babu
quelle
Eine Möglichkeit, die Leistungsprobleme von Reflection in einigen Fällen zu vermeiden, besteht darin, eine Klasse Woozlebeim Start andere Klassen untersuchen zu lassen, um festzustellen, welche über eine statische RegisterAsWoozleHelper()Methode verfügen , und alle gefundenen Methoden mit einem Rückruf aufzurufen, mit dem sie Woozleüber sich selbst berichten können, um dies zu vermeiden müssen Reflection verwenden, während z. B. Daten deserialisiert werden.
Supercat
9

Wie der Name selbst andeutet, spiegelt er das wider, was er beispielsweise für eine Klassenmethode usw. enthält, abgesehen von der Bereitstellung einer Funktion zum dynamischen Aufrufen einer Methode, die zur Laufzeit eine Instanz erstellt.

Es wird von vielen Frameworks und Anwendungen unter dem Holz verwendet, um Dienste aufzurufen, ohne den Code tatsächlich zu kennen.

Mohammed Sarfaraz
quelle
7

Durch Reflexion können Sie allgemeineren Code schreiben. Sie können ein Objekt zur Laufzeit erstellen und seine Methode zur Laufzeit aufrufen. Somit kann das Programm stark parametrisiert werden. Es ermöglicht auch die Introspektion des Objekts und der Klasse, um seine Variablen und Methoden zu erkennen, die der Außenwelt ausgesetzt sind.

Saumik Gupta
quelle
6

Reflectionhat viele Verwendungszwecke . Das, mit dem ich besser vertraut bin, ist, Code im laufenden Betrieb erstellen zu können.

IE: dynamische Klassen, Funktionen, Konstruktoren - basierend auf beliebigen Daten (xml / array / sql results / hardcoded / etc ..)

Ess Kay
quelle
1
Diese Antwort wäre viel besser, wenn Sie nur ein ungewöhnliches Beispiel für generierten Code geben würden, entweder aus einem SQL-Ergebnis oder einer XML-Datei usw.
ThisClark
Kein Problem. Ich habe Reflection in einer Windows-Anwendung verwendet, die die Schnittstelle basierend auf XML aus einer Datenbank dynamisch generiert.
Ess Kay
Grundsätzlich gibt es eine Klasse, die ich erstellt habe und die dem Benutzer einen Bericht zeigt. Dieser Bericht enthält Parameter wie die Datums-ID (von bis) oder was auch immer. Diese Informationen werden in XML gespeichert. Also haben wir zuerst eine Berichtsauswahl. Basierend auf dem ausgewählten Bericht erhält das Formular die XML. Sobald die XML-Datei abgerufen wurde, wird mithilfe der Reflektion eine Klasse mit Feldern erstellt, die auf reflektierten Typen basieren. Sobald Sie zu einem anderen Bericht wechseln, wird der Slate gelöscht und basierend auf der XML werden neue Felder generiert. Es ist also im Wesentlichen eine dynamische Form, die auf Reflexion basiert. Ich habe auch auf andere Weise verwendet, aber dies sollte ausreichend sein. Hoffnung, die hilft
Ess Kay
3

Ich möchte diese Frage anhand eines Beispiels beantworten. Zunächst generiert das HibernateProjekt Anweisungen, um die Kluft zwischen der laufenden Anwendung und dem Persistenzspeicher zu überbrücken. Wenn sich Dinge in der Domäne ändern, muss der über sie Bescheid wissen, um sie im Datenspeicher zu speichern und umgekehrt.Reflection APICRUDHibernate

Alternativ funktioniert Lombok Project. Es wird nur Code zur Kompilierungszeit eingefügt, was dazu führt, dass Code in Ihre Domänenklassen eingefügt wird. (Ich denke, es ist OK für Getter und Setter)

HibernateDiese Option wurde ausgewählt, reflectionda sie nur minimale Auswirkungen auf den Erstellungsprozess einer Anwendung hat.

Und von Java 7 haben wir MethodHandles, was funktioniert als Reflection API. In Projekten kopieren wir zum Arbeiten mit Loggern einfach den nächsten Code:

Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName());

Weil es in diesem Fall schwierig ist, Tippfehler zu machen.

BSeitkazin
quelle
3

Wie ich es am besten finde, anhand eines Beispiels zu erklären, und keine der Antworten scheint dies zu tun ...

Ein praktisches Beispiel für die Verwendung von Reflexionen wäre ein in Java geschriebener Java Language Server oder ein in PHP geschriebener PHP Language Server usw. Language Server bietet Ihren IDE-Funktionen wie Autocomplete, Sprung zur Definition, Kontexthilfe, Hinweistypen und mehr. Damit alle Tag-Namen (Wörter, die automatisch vervollständigt werden können) alle möglichen Übereinstimmungen während der Eingabe anzeigen, muss der Sprachserver alles über die Klasse überprüfen, einschließlich Dokumentblöcke und privater Mitglieder. Dafür braucht es eine Reflexion dieser Klasse.

Ein anderes Beispiel wäre ein Unit-Test einer privaten Methode. Eine Möglichkeit, dies zu tun, besteht darin, eine Reflexion zu erstellen und den Anwendungsbereich der Methode in der Einrichtungsphase des Tests öffentlich zu machen. Natürlich kann man argumentieren, dass private Methoden nicht direkt getestet werden sollten, aber das ist nicht der Punkt.

cprn
quelle