Maison  >  Article  >  Java  >  Comment améliorer l'efficacité de l'utilisation de la réflexion Java

Comment améliorer l'efficacité de l'utilisation de la réflexion Java

little bottle
little bottleavant
2019-04-28 16:33:583975parcourir

Dans notre travail quotidien ou nos entretiens, nous rencontrons souvent le point de connaissance de la « réflexion ». Grâce à la « réflexion », nous pouvons obtenir dynamiquement des informations sur les objets et appeler de manière flexible des méthodes d'objet, etc., mais en même temps, lors de leur utilisation, avec l'émergence d'un autre son, c'est-à-dire la « réflexion » est très lente et doit être utilisée avec parcimonie. La réflexion est-elle vraiment lente ? À quel point est-ce plus lent que lorsque nous créons habituellement des objets et appelons des méthodes ? Je suppose que beaucoup de gens ne l'ont jamais testé, ils l'ont simplement « entendu ». Faisons l'expérience directe de la « réflexion » directement à travers quelques cas de test.

Texte

Préparez l'objet de test

Définissez d'abord une classe de test TestUser, qui n'a que les attributs id et name, ainsi que leurs méthodes getter/setter, et un self- Définir la méthode sayHi.

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;
    }
}

Test pour créer 1 million d'objets

// 通过普通方式创建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
// 通过反射方式创建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

Dans les deux méthodes de test ci-dessus, l'auteur a testé chacune d'elles 5 fois, a pris une moyenne de leur consommation de temps et du résultat Vous pouvez voir de les résultats sont que l'un est de 10 ms et l'autre de 926 ms. Lorsque 1 million d'objets sont créés, la réflexion est en réalité environ 90 fois plus lente. wow ? L'écart est-il si grand ? La réflexion est-elle vraiment si lente ? Ensuite, l'auteur change la posture de réflexion et continue de la tester pour voir quel est le résultat ?

// 通过缓存反射方式创建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

En fait, grâce au code, nous pouvons constater que la méthode Class.forName prend plus de temps. Elle appelle en fait une méthode locale, à travers laquelle la JVM est invitée à rechercher et à charger la classe spécifiée. Par conséquent, lorsque nous l'utilisons dans le projet, nous pouvons mettre en cache l'objet Class renvoyé par Class.forName et l'obtenir directement à partir du cache lors de sa prochaine utilisation, ce qui améliore considérablement l'efficacité d'obtention de Class. De la même manière, lorsque nous obtenons un constructeur, une méthode et d'autres objets, nous pouvons également les mettre en cache pour éviter une création fastidieuse à chaque utilisation.

Test de la méthode d'appel réflexif

@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
@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

Ici, nous réfléchissons et appelons la méthode sayHi 100 millions de fois. Après avoir appelé method.setAccessible(true), avons constaté qu'elle est presque moitié plus rapide<.>. En regardant l'API, nous pouvons voir que jdk effectuera des contrôles d'accès de sécurité lors de la définition du champ d'acquisition et des méthodes d'appel, et de telles opérations prendront beaucoup de temps, donc vous pouvez désactiver les contrôles de sécurité via setAccessible(true), ainsi améliorant l'efficacité de la réflexion.

Réflexion ultime

En plus des méthodes ci-dessus, existe-t-il un moyen d'utiliser la réflexion à l'extrême ? Nous présentons ici ReflectASM, une boîte à outils de réflexion haute performance. Il s'agit d'un mécanisme de réflexion implémenté via la génération de bytecode. Ce qui suit est une comparaison des performances avec la réflexion Java.

Comment améliorer lefficacité de lutilisation de la réflexion Java

Conclusion

Enfin, pour résumer, afin de mieux utiliser la réflexion, nous devons charger la configuration pertinente et les données requises pour la réflexion dans la mémoire au démarrage du projet , puis exécuter Chaque étape récupère ces métadonnées du cache pour les opérations de réflexion. Il ne faut pas avoir peur de la réflexion. La machine virtuelle est constamment optimisée, tant que nous utilisons la bonne méthode, ce n'est pas aussi lent que « la rumeur ». Lorsque nous avons la recherche ultime de la performance, nous pouvons envisager. utiliser des packages tiers pour coder directement pour fonctionner.

Tutoriels associés : Tutoriel vidéo Java

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer