Heim > Java > javaLernprogramm > So verbessern Sie die Effizienz der Verwendung von Java Reflection

So verbessern Sie die Effizienz der Verwendung von Java Reflection

little bottle
Freigeben: 2019-04-28 16:40:53
nach vorne
3992 Leute haben es durchsucht

In unserer täglichen Arbeit oder in Interviews stoßen wir häufig auf den Wissenspunkt „Reflexion“. Durch „Reflexion“ können wir Objektinformationen dynamisch abrufen und Objektmethoden usw. flexibel aufrufen, aber gleichzeitig, wenn wir sie verwenden Beim Auftauchen eines anderen Lautes erfolgt die „Reflexion“ sehr langsam und sollte sparsam eingesetzt werden. Ist die Reflexion wirklich langsam? Wie viel langsamer ist es, als wenn wir normalerweise Objekte erstellen und Methoden aufrufen? Ich denke, viele Leute haben es noch nie getestet, sie haben es nur „gehört“. Lassen Sie uns die „Reflexion“ anhand einiger Testfälle direkt erleben.

Text

Bereiten Sie das Testobjekt vor

Definieren Sie zunächst eine Testklasse TestUser, die nur die Attribute id und name sowie deren Getter/Setter-Methoden enthält, und a self- Definieren Sie die sayHi-Methode.

public class TestUser {    private Integer id;    private String name;    
    public String sayHi(){        return "hi";
    }    public Integer getId() {        return id;
    }    public void setId(Integer id) {        this.id = id;
    }    public String getName() {        return name;
    }    public void setName(String name) {        this.name = name;
    }
}
Nach dem Login kopieren

Test zum Erstellen von 1 Million Objekten

// 通过普通方式创建TestUser对象@Testpublic void testCommon(){    long start = System.currentTimeMillis();
    TestUser user = null;    int i = 0;    while(i<1000000){
        ++i;
        user = new TestUser();
    }    long end = System.currentTimeMillis();
    System.out.println("普通对象创建耗时:"+(end - start ) + "ms");
}//普通对象创建耗时:10ms
Nach dem Login kopieren
// 通过反射方式创建TestUser对象@Testpublic void testReflexNoCache() throws Exception {    long start = System.currentTimeMillis();
    TestUser user = null;    int i = 0;    while(i<1000000){
        ++i;
        user = (TestUser) Class.forName("ReflexDemo.TestUser").newInstance();
    }    long end = System.currentTimeMillis();
    System.out.println("无缓存反射创建对象耗时:"+(end - start ) + "ms");
}//无缓存反射创建对象耗时:926ms
Nach dem Login kopieren

Bei den beiden oben genannten Testmethoden hat der Autor jede von ihnen fünfmal getestet, einen Durchschnitt ihres Zeitverbrauchs und der Ausgabe ermittelt, die Sie sehen können Das Ergebnis ist, dass eines 10 ms und das andere 926 ms beträgt. Wenn 1 Million Objekte erstellt werden, ist die Reflexion tatsächlich etwa 90-mal langsamer. Was zum Teufel? Ist die Lücke so groß? Ist die Reflexion wirklich so langsam? Als nächstes ändert der Autor die Reflexionshaltung und testet sie weiter, um zu sehen, was das Ergebnis ist?

// 通过缓存反射方式创建TestUser对象@Testpublic void testReflexWithCache() throws Exception {    long start = System.currentTimeMillis();
    TestUser user = null;
    Class rUserClass = Class.forName("RefleDemo.TestUser");    int i = 0;    while(i<1000000){
        ++i;
        user = (TestUser) rUserClass.newInstance();
    }    long end = System.currentTimeMillis();
    System.out.println("通过缓存反射创建对象耗时:"+(end - start ) + "ms");
}//通过缓存反射创建对象耗时:41ms
Nach dem Login kopieren

Tatsächlich können wir anhand des Codes feststellen, dass die Methode Class.forName zeitaufwändiger ist. Sie ruft tatsächlich eine lokale Methode auf, über die die JVM aufgefordert wird, die angegebene Klasse zu finden und zu laden. Wenn wir es im Projekt verwenden, können wir daher das von Class.forName zurückgegebene Klassenobjekt zwischenspeichern und es bei der nächsten Verwendung direkt aus dem Cache abrufen, was die Effizienz beim Abrufen der Klasse erheblich verbessert. Auf die gleiche Weise können wir, wenn wir Konstruktor-, Methoden- und andere Objekte erhalten, diese auch zur Verwendung zwischenspeichern, um eine zeitaufwändige Erstellung bei jeder Verwendung zu vermeiden.

Testen der reflektierenden Aufrufmethode

@Testpublic void testReflexMethod() throws Exception {    long start = System.currentTimeMillis();
    Class testUserClass = Class.forName("RefleDemo.TestUser");
    TestUser testUser = (TestUser) testUserClass.newInstance();
    Method method = testUserClass.getMethod("sayHi");    int i = 0;    while(i<100000000){
        ++i;
        method.invoke(testUser);
    }    long end = System.currentTimeMillis();
    System.out.println("反射调用方法耗时:"+(end - start ) + "ms");
}//反射调用方法耗时:330ms
Nach dem Login kopieren
@Testpublic void testReflexMethod() throws Exception {    long start = System.currentTimeMillis();
    Class testUserClass = Class.forName("RefleDemo.TestUser");
    TestUser testUser = (TestUser) testUserClass.newInstance();
    Method method = testUserClass.getMethod("sayHi");    int i = 0;    while(i<100000000){
        ++i;
        method.setAccessible(true);
        method.invoke(testUser);
    }    long end = System.currentTimeMillis();
    System.out.println("setAccessible=true 反射调用方法耗时:"+(end - start ) + "ms");
}//setAccessible=true 反射调用方法耗时:188ms
Nach dem Login kopieren

Hier reflektieren und rufen wir die sayHi-Methode 100 Millionen Mal auf. Nach dem Aufruf von method.setAccessible(true) stellen wir fest, dass sie fast halb so schnell ist. Wenn wir uns die API ansehen, können wir sehen, dass JDK beim Festlegen des Erfassungsfelds und beim Aufrufen von Methoden Sicherheitszugriffsprüfungen durchführt und solche Vorgänge zeitaufwändig sind. Sie können daher Sicherheitsprüfungen über setAccessible (true) deaktivieren Verbesserung der Reflexionseffizienz.

Ultimative Reflexion

Gibt es zusätzlich zu den oben genannten Methoden eine Möglichkeit, die Reflexion bis zum Äußersten zu nutzen? Hier stellen wir ReflectASM vor, ein leistungsstarkes Reflexions-Toolkit. Es handelt sich um einen Reflexionsmechanismus, der durch Bytecode-Generierung implementiert wird. Im Folgenden finden Sie einen Leistungsvergleich mit der Java-Reflexion.

So verbessern Sie die Effizienz der Verwendung von Java Reflection

Fazit

Abschließend zusammenfassend: Um die Reflektion besser nutzen zu können, sollten wir die relevanten Konfigurationen und Daten, die für die Reflektion erforderlich sind, beim Start des Projekts in den Speicher laden und dann ausführen Jede Stufe ruft diese Metadaten aus dem Cache für Reflektionsvorgänge ab. Sie müssen keine Angst vor Reflexion haben. Solange wir die richtige Methode verwenden, ist sie nicht so langsam wie „gemunkelt“. Verwendung von Paketen von Drittanbietern für den direkten Codebetrieb.

Verwandte Tutorials: Java-Video-Tutorial

Das obige ist der detaillierte Inhalt vonSo verbessern Sie die Effizienz der Verwendung von Java Reflection. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:oschina.net
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage