Merkwürdige Ganzzahl-Boxen in Java
-
01-10-2019 - |
Frage
Ich habe gerade Säge Code ähnlich wie diese:
public class Scratch
{
public static void main(String[] args)
{
Integer a = 1000, b = 1000;
System.out.println(a == b);
Integer c = 100, d = 100;
System.out.println(c == d);
}
}
Wenn RAN, dieser Block von Code ausdrucken:
false
true
Ich verstehe, warum die erste false
ist: weil die beiden Objekte separate Objekte sind, so dass die ==
die Referenzen vergleicht. Aber ich kann nicht herausfinden, warum die zweite Anweisung Rückkehr true
? Gibt es eine seltsame Autoboxing Regel, dass Tritte in, wenn der Wert eines Integer ist in einem bestimmten Bereich? Was ist denn hier los?
Lösung
Die true
Linie ist tatsächlich von der Sprachspezifikation garantiert. Abschnitt 5.1.7 :
Wenn der Wert p eingerahmt wird wahr, falsch, ein Byte, ein Zeichen im Bereich \ U0000 zu \ u007f oder ein int oder Kurz Zahl zwischen -128 und 127, dann lassen R1 und R2 sind die Ergebnisse von zwei beliebigen Boxen Umwandlungen von p. Es ist immer der Fall, dass r 1 == r2.
Die Diskussion geht weiter, was darauf hindeutet, dass, obwohl Ihre zweite Zeile der Ausgabe gewährleistet ist, wird die erste nicht (siehe letzter Absatz zitiert unten):
Idealerweise Boxen ein primitiver gegeben p-Wert würde eine immer Ausbeute identischer Bezug. In der Praxis wird diese kann nicht möglich sein, vorhandene Implementierungstechniken. Die Regeln oben ist ein pragmatischer Kompromiss. Das Nachsatz erfordert darüber bestimmte gemeinsame Werte immer eingerahmt werden in nicht zu unterscheiden Objekte. Das Implementierung kann diese zwischenspeichern, träge oder eifrig.
Für andere Werte, diese Formulierung nicht zulässt, keine Annahmen über die Identität der boxed Werte auf die Programmierer Teil. Dies würde es ermöglichen (Aber nicht erforderlich) Austausch einiger oder alle diese Referenzen.
Damit wird sichergestellt, dass in den meisten üblichen Fällen wird das Verhalten der gewünschte, ohne eine ungebührliche Auferlegung Leistungseinbuße, insbesondere auf kleine Geräte. Weniger Speicher begrenzt Implementierungen könnte zum Beispiel, cachen alle Zeichen und kurze Hosen, wie auch als ganze Zahlen und sehnt sich in der Bereich von -32K -. + 32K
Andere Tipps
public class Scratch
{
public static void main(String[] args)
{
Integer a = 1000, b = 1000; //1
System.out.println(a == b);
Integer c = 100, d = 100; //2
System.out.println(c == d);
}
}
Ausgang:
false
true
Yep der erste Ausgang zum Vergleichen von Referenz erzeugt; ‚A‘ und ‚b‘ - das sind zwei unterschiedliche Referenz. In Nummer 1 sind eigentlich zwei Referenzen geschaffen, die ähnlich ist wie -
Integer a = new Integer(1000);
Integer b = new Integer(1000);
Die zweite Ausgabe erzeugt wird, weil die JVM
Speicher zu speichern versucht, wenn die Integer
in einem Bereich fallen (von -128 bis 127). Am Punkt 2 keine neue Referenz vom Typ Integer ist für ‚d‘ erstellt. Stattdessen ein neues Objekt für die Integer-Typ Referenzgröße ‚d‘ zu schaffen, ist es nur mit zuvor erstellten Objekt referenziert von ‚c‘ zugeordnet. Alle diese werden von JVM
getan.
Diese Daten speichern Regeln nicht nur für Integer. für Speicher sparend Zweck zwei Instanzen der folgenden Wrapper-Objekte (während durch Boxen erstellt), werden es immer sein == wo ihre primitiven Werte gleich sind -
- Boolean
- Byte
- Charakter von \ u0000 zu
\u007f
(7f ist 127 dezimal) - Short und Integer von -128 127
Integer-Objekte in einem gewissen Bereich (ich denke, vielleicht -128 bis 127) erhalten im Cache gespeichert und wiederverwendet. Die ganzen Zahlen außerhalb dieses Bereichs jedes Mal ein neues Objekt erhalten.
Ja, es ist eine seltsame Autoboxing Regel, dass Tritte in, wenn die Werte in einem bestimmten Bereich. Wenn Sie eine Konstante zu einem Objektvariablen zuweisen, nichts in der Sprachdefinition sagt ein neues Objekt muss erstellt werden. Es kann ein vorhandenes Objekt aus dem Cache wiederverwendet werden.
In der Tat wird die JVM in der Regel speichert einen Cache von kleinen ganzen Zahlen für diesen Zweck sowie Werte wie Boolean.TRUE und Boolean.FALSE.
Das ist ein interessanter Punkt. In dem Buch Effective Java immer außer Kraft zu setzen schlägt gleich für Ihre eigenen Klassen. Auch, dass Gleichheit für zwei Objektinstanzen einer Java-Klasse zu überprüfen, verwenden Sie immer die Methode entspricht.
public class Scratch
{
public static void main(String[] args)
{
Integer a = 1000, b = 1000;
System.out.println(a.equals(b));
Integer c = 100, d = 100;
System.out.println(c.equals(d));
}
}
Rückgabe:
true
true
Meine Vermutung ist, dass Java einen Cache von kleinen ganzen Zahlen hält, die bereits sind ‚verpackt‘, weil sie so sehr verbreitet sind und es spart eine verdammt viel Zeit, um die Weiterverwendung ein vorhandenes Objekt als ein neues zu erstellen.
In Java die Box-Arbeiten im Bereich zwischen -128 und 127 für eine ganze Zahl. Wenn Sie mit Zahlen in diesem Bereich können Sie es mit dem Operator == vergleichen. Für Integer außerhalb des Bereichs Objekte haben Sie Verwendung entspricht.
Direkte Zuweisung eines int wörtlichen zu einer Integer Referenz ist ein Beispiel für Auto-Box, wo der wörtliche Wert Codeobjekt Umwandlung vom Compiler behandelt wird.
So während der Kompilierung Phase Compiler wandelt Integer a = 1000, b = 1000;
zu Integer a = Integer.valueOf(1000), b = Integer.valueOf(1000);
.
Es ist also Integer.valueOf()
Verfahren, das gibt uns tatsächlich die Integer-Objekte, und wenn wir auf dem Quellcode von Integer.valueOf()
Methode sehen wir eindeutig die Methode Caches integer Objekte im Bereich von -128 bis 127 (einschließlich) sehen.
/**
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Also statt der Schaffung und neue integer Objekte Rückkehr Integer.valueOf()
die Methode zurückgibt Integer aus dem internen IntegerCache
Objekten, wenn die übergebene int wörtlichen größer als -128 und kleiner als 127.
Java-Caches dieser Integer-Objekte, da dieser Bereich von ganzen Zahlen eine Menge in der täglichen Programmierung verwendet wird, die indirekt etwas Speicher speichert.
Der Cache auf der ersten Verwendung initialisiert wird, wenn die Klasse in dem Speicher wegen des statischen Blockes geladen wird. Die maximale Reichweite des Cache kann durch die -XX:AutoBoxCacheMax
JVM-Option gesteuert werden.
Dieses Caching-Verhalten ist nicht anwendbar für Integer nur Objekte, ähnlich wie Integer.IntegerCache wir haben ByteCache, ShortCache, LongCache, CharacterCache
für Byte, Short, Long, Character
auch sind.
Sie können lesen Sie mehr auf meinem Artikel Java Integer Cache - Warum Integer.valueOf (127) == Integer.valueOf (127) wahr .
In Java 5 wurde eine neue Funktion eingeführt, um den Speicher zu sparen und die Leistung verbessern für Integer-Typen Handlings-Objekte. Integer-Objekte werden im Cache gespeichert intern und über die gleichen referenzierte Objekte wiederverwendet werden.
-
Dies gilt für Integer-Wert in einem Bereich zwischen -127 bis +127 (Max Integer-Wert).
-
Dieses Integer-Caching funktioniert nur auf Autoboxing. Integer Objekte nicht im Cache gespeichert werden, wenn sie den Konstruktor gebaut verwenden.
Für weitere Einzelheiten pls geht durch unter-Link:
Wenn wir den Quellcode Integer
obeject überprüfen, werden wir die Quelle valueOf
Methode finden wie diese:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
, die erklären können, warum Integer
Objekte, die im Bereich von -128 (Integer.low
) bis 127 (Integer.high
), sind die gleichen referenzierte Objekte während des Autoboxing. Und wir können sehen, gibt es eine Klasse IntegerCache
kümmert sich um die Integer
Cache-Array, das eine private statische innere Klasse von Integer
Klasse ist.
Es ist ein weiteres interessantes Beispiel kann uns helfen, diese seltsame Situation zu verstehen:
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Class cache = Integer.class.getDeclaredClasses()[0];
Field myCache = cache.getDeclaredField("cache");
myCache.setAccessible(true);
Integer[] newCache = (Integer[]) myCache.get(cache);
newCache[132] = newCache[133];
Integer a = 2;
Integer b = a + a;
System.out.printf("%d + %d = %d", a, a, b); //The output is: 2 + 2 = 5
}