Avant de commencer le texte principal de cet article, jetons un coup d'œil au code suivant:
Le rôle d'IntegerCache de la classe Integer en Java
Nom du package: java.lang
Nom du fichier: Integer.java
Nom de la méthode: IntegerCache
Le code de la méthode est le suivant:
classe statique privée IntegerCache {statique final int high; Cache entier final statique []; statique {final int low = -128; // La valeur élevée peut être configurée par la propriété int h = 127; if (IntegerCacheHighPropValue! = null) {// Utilisez long.decode ici pour éviter d'invoquer des méthodes qui // nécessitent le cache d'autoboxing d'Integer pour être initialisé int i = long.decode (IntegerCacheHighPropValue) .IntValue (); i = math.max (i, 127); // La taille maximale du tableau est Integer.max_value h = math.min (i, Integer.max_value - -low); } high = h; cache = nouvel entier [(élevé - bas) + 1]; int j = bas; pour (int k = 0; k <cache.length; k ++) cache [k] = nouveau entier (j ++); } private IntegerCache () {}}Nous voyons dans le code que le bas est -128 et que le haut est 127. De cette façon, dans la programmation Java, si vous souhaitez utiliser un objet dans l'intervalle -128-127, vous utiliserez directement l'objet dans ce cache.
Ce qui précède est une brève introduction pour aider tout le monde à comprendre IntegerCache. Ce qui suit est le texte principal de cet article:
introduction
Il y a 5 ans, j'ai publié un article sur Hongrois sur la façon de changer IntegerCache dans JDK. Cette approche doit en fait aller profondément dans Java Runtime et n'est pas réellement utilisée dans les scénarios. Lorsque vous développez ce code de recherche, vous pouvez mieux comprendre le fonctionnement de la réflexion et comment la classe Integer les implémente.
La classe Integer a un IntegerCache nommé privé nommé, qui contient des objets entiers avec des valeurs allant de -127 à 128.
Lorsque le code doit être enfermé de Type int dans un objet entier et que la valeur est dans cette plage, le runtime Java utilisera ce cache au lieu de créer un nouvel objet entier. Ceci est principalement pour les considérations d'optimisation des performances. Nous devons garder à l'esprit que de nombreuses valeurs int sont souvent dans cette plage du programme (comme l'indice des indices d'un tableau).
L'effet secondaire de cela est que, plusieurs fois, lorsque vous utilisez l'opérateur de signe égal pour comparer deux objets entiers, tant que la valeur est à portée, elle est valide. Ceci est typique des tests unitaires. En mode d'exécution, lorsque la valeur est supérieure à 128, l'exécution de code échouera.
L'utilisation de la réflexion pour accéder aux classes IntegerCache peut provoquer des effets secondaires étranges, notez que cela affecte l'intégralité de la JVM. Si un servlet redéfinit une petite valeur de cache entier, tous les autres servlets fonctionnant sous le même Tomcat rencontrent le même problème.
Il existe d'autres articles ci-dessus dans Lukas Eder et SitePoint.
Maintenant que je joue avec les premières sorties de Java 9, tout ce que j'ai toujours à faire, c'est expérimenter les nouvelles versions Java. Avant de commencer, jetons un coup d'œil sur la façon de le faire dans Java 8.
Dans l'article de Lukas, j'ai publié son exemple de code ici:
Importer java.lang.reflect.field; import java.util.random; public class Entropy {public static void main (String [] args) lève une exception {// Extraire l'IntegerCache via la classe de réflexion <<? > cllazz = class.forname ("java.lang.integer $ IntegerCache"); Field Field = Clazz.getDeclaredField ("Cache"); field.setAccessible (true); Entier [] cache = (entier []) field.get (Clazz); // Réécrivez le cache entier pour (int i = 0; i <cache.length; i ++) {cache [i] = new Integer (new Random (). NextInt (cache.length)); } // prouve le hasard pour (int i = 0; i <10; i ++) {System.out.println ((entier) i); }}}Ce code accède à IntegerCache via la réflexion, puis utilise des valeurs aléatoires pour remplir le cache (Naughty!).
Nous essayons d'exécuter le même code dans Java 9, ne vous attendez pas à vous amuser. Lorsque quelqu'un essaie de le violer, il constatera que Java 9 est plus restrictif.
Exception dans Thread "Main" java.lang.reflect.inaccessibleobjectexception: Impossible de rendre le champ final statique final java.lang.integer [] java.lang.integer $ IntegerCache.cache accessible: module java.base ne fait pas "opent java.lang"
Le programme lance une exception, qui ne se produira pas dans Java 8. Il équivaut à dire que les objets ne sont pas basés sur un modèle. En raison du module Java.base, il fait partie intégrante du JDK. Il est automatiquement importé lorsque chaque programme Java est démarré et que les modules sans nom ne sont pas autorisés à être ouverts. Cette exception est lancée lorsque nous essayons de définir la propriété accessible au champ.
Les objets auxquels nous pouvons facilement accéder dans Java 8 ne sont désormais pas accessibles dans Java 9 car le nouveau système de modules le protège. Le code ne peut accéder qu'à des champs, des méthodes et d'autres informations accessibles par réflexion, uniquement si la classe se trouve dans le même module, ou si le module a un package ouvert pour l'accès à la réflexion. Ceci peut être implémenté via le fichier de définition du module module-info.java:
module mymodule {export com.javax0.module.demo; ouvre com.javax0.module.demo;} Ce module Java.base n'est pas nécessaire pour l'ouvrir seul pour l'accès à la réflexion, en particulier pour les modules sans nom. Si nous créons un module et le nommez, le message d'erreur contiendra le nom du module.
Pouvons-nous ouvrir des modules dans le programme? Le module java.lang.reflect.Module a une méthode d'addition qui peut être effectuée.
Est-ce possible?
La mauvaise nouvelle pour les développeurs est: ce n'est pas possible. Il ne peut ouvrir un package dans un module dans un autre module, et le package a été ouvert dans ce module en appelant cette méthode. Cette méthode ne peut permettre que les modules soient transmis à un autre module, à condition que l'autre module ait ouvert le même package d'une manière ou d'une autre, et ne peut pas ouvrir des packages non ouverts (Note du traducteur: c'est difficile à comprendre, n'est-ce pas?).
Mais en même temps, la bonne nouvelle est: Java 9 n'est pas aussi facile à casser que Java 8. Au moins cette vulnérabilité est fermée. Il semble que Java commence à se développer vers un niveau professionnel, pas seulement un jouet (note du traducteur: qui a dit que Java était un jouet?). Dans un avenir proche, vous pouvez migrer très sérieusement les projets en RPG et COBOL vers Java. (Désolé, je plaisante)
Résumer
Ce qui précède est l'intégralité du contenu de cet article. J'espère que le contenu de cet article a une certaine valeur de référence pour l'étude ou le travail de chacun. Si vous avez des questions, vous pouvez laisser un message pour communiquer. Merci pour votre soutien à wulin.com.
Cet article est traduit de: https://dzone.com/articles/hacking-the-integercache-in-java-9