Préface
Cet article présente principalement un contenu pertinent sur Integer en Java et le partage pour votre référence et votre apprentissage. Je ne dirai pas beaucoup ci-dessous, jetons un coup d'œil à l'introduction détaillée ensemble.
De vrais parasites
Il y a quelques jours, j'ai vu un article partagé par mes moments "Le mécanisme de transmission des paramètres des fonctions Java - le comprenez-vous vraiment?》
Certains déclencheurs ont déjà été étudiés dans entier de Java, alors j'ai écrit cet article, en espérant que cela vous sera utile.
échange
Voyons d'abord un exemple.
Veuillez utiliser Java pour compléter la fonction d'échange et échanger les valeurs de deux types entiers.
Public static void test () lève une exception {entier a = 1, b = 2; échange (a, b); System.out.println ("a =" + a + ", b =" + b);} échange de void statique (entier a, entier b) {// parties qui doivent être implémentées} d'abord
Si vous ne comprenez pas comment les objets Java sont alloués en mémoire et comment les méthodes transmettent les paramètres, vous pouvez écrire le code suivant.
public statique void swapone (entier a, entier b) lève une exception {entier atempValue = a; a = b; b = atempValue;} Les résultats de l'exécution montrent que les valeurs A et B ne sont pas échangées.
Voyons donc comment les objets Java sont alloués en mémoire lorsque le programme ci-dessus s'exécute:
Affectation d'adresse de l'objet
À partir de cela, nous pouvons voir que les tableaux variables locaux des deux méthodes contiennent des références aux adresses de données réelles des objets A et B.
La fonction d'échange implémentée ci-dessus échange uniquement des références à la variable locale A et la variable locale B dans la fonction Swap, et n'échange pas les données réelles dans le tas JVM.
Par conséquent, les données référencées par A et B dans la fonction principale ne sont pas échangées, donc les A et B des variables locales de la fonction principale ne changent pas.
Alors, comment fonctionnez-vous lors de l'échange des données dans la fonction principale?
La deuxième fois
Selon la pratique ci-dessus, pouvons-nous envisager d'échanger des valeurs de données de A et B sur le tas JVM?
Apprenons brièvement sur l'objet entier. Il n'a qu'une valeur de type int objet au niveau de l'objet pour représenter la valeur de l'objet.
Nous utilisons donc la réflexion pour modifier la valeur, le code est le suivant:
public static void swaptwo (Integer A1, Integer B1) lève l'exception {Field ValueField = Integer.Class.getDeclaredField ("Value"); ValueField.SetAccessible (true); int tempavalue = valuefield.getInt (a1); ValueField.SetInt (A1, B1.IntValue ()); ValueField.SetInt (B1, tempavalue);}Les résultats de l'opération sont conformes aux attentes.
surprendre
Une fois le programme ci-dessus exécuté, ce qui se passera si je déclare un Integer c = 1, d = 2;
L'exemple de programme est le suivant:
public static void swaptwo (Integer A1, Integer B1) lève l'exception {Field ValueField = Integer.Class.getDeclaredField ("Value"); ValueField.SetAccessible (true); int tempavalue = valuefield.getInt (a1); ValueField.SetInt (A1, B1.IntValue ()); ValueField.SetInt (b1, tempavalue);} public static void testThere () lève une exception {entier a = 1, b = 2; swaptwo (a, b); System.out.println ("a =" + a + "; b =" + b); Entier c = 1, d = 2; System.out.println ("C =" + C + "; D =" + D);}Les résultats de sortie sont les suivants:
a = 2; b = 1c = 2; d = 1
Surprise ou pas! Accident ou pas! Stimulant ou pas!
En profondeur
Que s'est-il passé exactement? Jetons un coup d'œil au code décompilé:
L'auteur a utilisé l'outil IDE pour décompiler directement ce fichier .class
Public Static Void TestTheRe () lève une exception {entier a = Integer.ValueOf (1); Entier b = entier.valueof (2); swaptwo (a, b); System.out.println ("a =" + a + "; b =" + b); Entier c = entier.valueof (1); Entier d = entier.valueof (2); System.out.println ("C =" + C + "; D =" + D);} Dans le processus de Java, boxant automatiquement le type d'origine int au type entier Integer.valueOf(int) est utilisée.
Il faut que cette méthode résume certaines opérations en interne, ce qui nous fait avoir un impact global après avoir modifié Integer.value .
Tout cela implique le code dans cette partie du code est collé à la fois (PS: L'auteur qui ne fait pas glisser est un bon codeur):
classe publique Integer {/ ** * @Since 1.5 * / public static Integer Value Of (int i) {if (i> = IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache [i + (-IntegerCache.Low)]; retourner un nouvel entier (i); } classe statique privée IntegerCache {statique final int low = -128; statique final int high; Cache entier final statique []; statique {// La valeur élevée peut être configurée par la propriété int h = 127; String IntegerCacheHighPropValue = Sun.Misc.vm.GetsAvedProperty ("Java.lang.integer.integerCache.high"); if (IntegerCacheHighPropValue! = null) {try {int i = paSeInt (IntegerCacheHighPropValue); i = math.max (i, 127); // La taille maximale du tableau est Integer.max_value h = math.min (i, Integer.max_value - (-low) -1); } catch (NumberFormatexception nfe) {// Si la propriété ne peut pas être analysée dans un int, ignorez-la. }} high = h; cache = nouvel entier [(élevé - bas) + 1]; int j = bas; pour (int k = 0; k <cache.length; k ++) cache [k] = nouveau entier (j ++); // plage [-128, 127] doit être interné (JLS7 5.1.7) ASSERT IntegerCache.high> = 127; } private IntegerCache () {}} Comme indiqué ci-dessus, Integer a une classe statique privée IntegerCache à l'intérieur, qui initialise statiquement un tableau entier contenant Integer.IntegerCache.low à java.lang.Integer.IntegerCache.high .
La plage de valeur de java.lang.Integer.IntegerCache.high est entre [127~Integer.MAX_VALUE - (-low) -1] .
Tous les objets renvoyés par la fonction Integer.valueOf(int) dans cet intervalle sont des décalages calculés sur la base de la valeur int et sont obtenus à partir du tableau Integer.IntegerCache.cache . L'objet est le même et aucun nouvel objet n'est créé.
Ainsi, lorsque nous modifions la valeur d' Integer.valueOf(1) , toutes les valeurs de retour d' Integer.IntegerCache.cache[ 1 - IntegerCache.low ] seront modifiées.
Je crois que votre QI devrait être compris. Si vous ne comprenez pas, veuillez appeler le 10086 dans la section des commentaires.
Ok, alors qu'en est-il de la pièce qui n'est pas dans [IntegerCache.low~IntegerCache.high) ?
De toute évidence, ils ont de la chance, pas mis en cache par Integercache, et chaque fois qu'ils arrivent, ils alloueront un morceau de terre (intérieur) (distribution) sur le JVM.
Rêverie
Et si je change le paramètre converti en type en int?
public static void testone () lève une exception {int a = 1, b = 2; swapone (a, b); System.out.println ("a =" + a + ", b =" + b);} statique void swapone (int a, int b) {// parties qui doivent être implémentées} Avec les compétences actuelles de l'auteur, il n'y a pas de solution. Les experts peuvent laisser des messages sur le compte officiel, merci beaucoup!
Jusqu'à présent, la partie d'échange a été terminée.
1 + 1
Regardons d'abord le code:
public static void testone () {int one = 1; int deux = un + un; System.out.printf ("deux =% D", deux);} Quelle est la sortie?
Si vous dites 2 pour être sûr, alors vous l'avez appris en vain, veuillez appeler le 95169 directement.
Je peux vous dire avec certitude que cela peut être n'importe quelle valeur dans l'intervalle [Integer.MIN_VALUE~Integer.MAX_VALUE] .
Surprise ou pas! Accident ou pas! Stimulant ou pas!
Coucons le code rôti un par un.
L'auteur a utilisé l'outil IDE pour décompiler directement ce fichier .class
public static void testone () {int one = 1; int deux = un + un; System.out.printf ("deux =% D", deux);} La variable deux ici n'a pas appelé dans teger.valueOf(int) , qui est différente de ce que j'imaginais. Je soupçonne que c'est le pot de l'IDE.
Vérifiez donc de manière décisive le bytecode compilé. Ce qui suit est quelques-uns des décodes de l'extrait:
LDC "Two =% D" iconst_1AnWarRay Java / Lang / ObjectDupiConst_0iload 2Invokestatic Java / Lang / Integer.Valueof (i) Ljava / Lang / Integer; AastoreinVokeVirtual Java / io / PriventStream.printf (Ljava / lang / string; [ljava / lang / objet;) ljava / io / printStream; pop;
On peut voir que c'est en effet le pot de l'IDE. Non seulement Integer.valueOf(int) est appelé une fois, mais un tableau d'objet est également créé.
Le code Java complet devrait ressembler à ceci:
public static void testone () {int one = 1; int deux = un + un; Objet [] params = {Integer.ValueOf (Two)}; System.out.printf ("deux =% d", params);} Donc, modifiez simplement la valeur d' Integer.IntegerCache.cache[2+128] avant que la méthode ne soit appelée, alors ajoutez un code à la partie d'initialisation statique de la classe.
public class OnePlusOne {static {try {class <?> cacheclazz = class.forname ("java.lang.integer $ IntegerCache"); Field CacheField = cacheclazz.getDeclaredField ("cache"); cacheField.SetAccessible (true); Entier [] cache = (entier []) cacheField.get (null); // change ici en 1 + 1 = 3 cache [2 + 128] = nouvel entier (3); } catch (exception e) {e.printStackTrace (); }} public static void testone () {int one = 1; int deux = un + un; System.out.printf ("deux =% D", deux); }}deux == 2?
Après avoir modifié la valeur d' Integer.IntegerCache.cache[2 + 128] , la variable est-elle deux égales à 2?
public static void testtwo () {int one = 1; int deux = un + un; System.out.println (deux == 2); System.out.println (Integer.ValueOf (Two) == 2);}La sortie de code ci-dessus est la suivante
Truefalse
Parce que deux == 2 n'implique pas la conversion de la boxe entière ou une comparaison du type d'origine, le 2 du type d'origine est toujours égal à 2.
La forme réelle de Integer.valueOf(two)==2 est Integer.valueOf(two).intValue == 2 , c'est-à-dire 3 == 2, donc c'est faux.
Ici, nous pouvons voir que si vous comparez une valeur de NULL avec une variable entière avec une variable int avec un signe double égal, une conception NullPointException sera lancée.
Quel type de sortie sera si la méthode ici est remplacée par System.out.println("Two=" + two) ? Vous pouvez l'essayer.
post-scriptum
Xcache
| gentil | Y a-t-il un cache | Valeur minimale | Valeur maximale |
|---|---|---|---|
| Booléen | aucun | - | - |
| Octet | Bytecache | -128 | 127 (fixe) |
| Court | Shortcache | -128 | 127 (fixe) |
| Personnage | Caractéristique | 0 | 127 (fixe) |
| Entier | Entier | -128 | java.lang.integer.integercache.high |
| Long | Cache | -128 | 127 (fixe) |
| Flotter | aucun | - | - |
| Double | aucun | - | - |
java.lang.integer.integercache.high
Après avoir lu la méthode pour obtenir un haut sun.misc.VM.getSavedProperty la classe IntegerCache, vous pouvez avoir les questions suivantes. Nous ne retarderons pas et n'utiliserons pas une méthode à une question-un.
1. Comment transmettre cette valeur dans le JVM?
Comme les propriétés du système, lorsque JVM est démarré, il est transmis en réglant -Djava.lang.Integer.IntegerCache.high=xxx .
2. Quelle est la différence entre cette méthode et System.getProperty ?
Afin de distinguer les paramètres requis par le système JVM des paramètres utilisés par l'utilisateur,
Lorsque java.lang.System.initializeSystemClass est démarré, les paramètres de démarrage seront enregistrés à deux endroits:
2.1 Les paramètres du système reçus par tous les JVM sont enregistrés dans Sun.Misc.vm.SavedProps.
Lorsque le JVM démarre, il appelle la méthode java.lang.System.initializeSystemClass pour initialiser la propriété.
Dans le même temps, la méthode sun.misc.VM.saveAndRemoveProperties sera également appelée pour supprimer les propriétés suivantes de java.lang.System.props :
Les propriétés énumérées ci-dessus sont tous les paramètres du système qui doivent être définis pour le démarrage JVM, donc pour les considérations de sécurité et les considérations d'isolement, séparez-les du System.Props accessible à l'utilisateur.
2.2 Enregistrer d'autres paramètres à l'exception des paramètres suivants requis pour le démarrage JVM dans java.lang.system.props.
PS: JDK 1.8.0_91 Utilisé par l'auteur
IntegerCache pour Java 9
Imaginez que le gameplay coquine ci-dessus apparaît dans le package de dépendance tiers, il y aura certainement un groupe de programmeurs qui deviendront fous (s'il vous plaît, n'essayez pas un si mauvais gameplay, les conséquences sont très graves).
Heureusement, Java 9 a restreint cela. Vous pouvez écrire le fichier module-fo.java dans le module correspondant, qui restreint l'utilisation de la réflexion pour accéder aux membres, etc. Après la déclaration au besoin, le code ne peut accéder qu'à des champs, des méthodes et d'autres informations accessibles par réflexion. Uniquement lorsque la classe est dans le même module, ou que le module a ouvert un package pour l'accès à réflexion. Pour plus de détails, veuillez vous référer à l'article:
Modifier IntegerCache dans Java 9?
Merci à Lydia et Asuka pour leurs précieux conseils et leur travail acharné sur la relecture.
Enfin, je voudrais partager avec vous un problème que je ne fais pas attention à la valeur entière en Java:
Regardons d'abord un extrait de code:
public static void main (String [] args) {Integer a1 = Integer.ValueOf (60); // Danielinbiti entier B1 = 60; System.out.println ("1: =" + (a1 == b1)); Entier A2 = 60; Entier b2 = 60; System.out.println ("2: =" + (a2 == b2)); Entier A3 = nouvel entier (60); Entier b3 = 60; System.out.println ("3: =" + (a3 == b3)); Entier A3 = nouvel entier (60); Entier b3 = 60; System.out.println ("3: =" + (a3 == b3)); Entier A4 = 129; Entier b4 = 129; System.out.println ("4: =" + (a4 == b4)); } Si le résultat de la comparaison de ce code n'est pas exécuté, je ne sais pas quelles sont les réponses.
Pour connaître cette réponse, cela implique les problèmes de tampon et de tas Java.
En Java, le type entier est un tampon pour les nombres entre -128-127, il est donc cohérent avec le signe égal. Mais pour les nombres non dans cette gamme, ils sont nouveaux dans le tas. Par conséquent, l'espace d'adressage est différent, il n'est donc pas égal.
Integer b3=60 , il s'agit d'un processus d'emballage, c'est-à-dire Integer b3=Integer.valueOf(60)
Par conséquent, à l'avenir, lorsque vous rencontrez entier, vous devez utiliser intValue() pour comparer si les valeurs sont égales.
Il n'y a pas de tampon pour le double.
Répondre
1: = vrai
2: = vrai
3: = faux
4: = faux
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.