java Java中奇怪的整数装箱
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3130311/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Weird Integer boxing in Java
提问by Joel
I just saw code similar to this:
我刚刚看到类似这样的代码:
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);
}
}
When ran, this block of code will print out:
运行时,此代码块将打印出:
false
true
I understand why the first is false: because the two objects are separate objects, so the ==compares the references. But I can't figure out, why is the second statement returning true? Is there some strange autoboxing rule that kicks in when an Integer's value is in a certain range? What's going on here?
我明白为什么第一个是false:因为这两个对象是单独的对象,所以==比较引用。但我想不通,为什么第二个语句返回true?当整数的值在某个范围内时,是否有一些奇怪的自动装箱规则?这里发生了什么?
采纳答案by Jon Skeet
The trueline is actually guaranteed by the language specification. From section 5.1.7:
该true行实际上是由语言规范保证的。从第 5.1.7 节:
If the value p being boxed is true, false, a byte, a char in the range \u0000 to \u007f, or an int or short number between -128 and 127, then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.
如果被装箱的值 p 是真、假、一个字节、一个 \u0000 到 \u007f 范围内的字符,或者一个 int 或 -128 到 127 之间的短数,那么让 r1 和 r2 是任何两个装箱转换的结果p. 的 r1 == r2 总是如此。
The discussion goes on, suggesting that although your second line of output is guaranteed, the first isn't (see the last paragraph quoted below):
讨论还在继续,这表明虽然你的第二行输出是有保证的,但第一行不是(见下面引用的最后一段):
Ideally, boxing a given primitive value p, would always yield an identical reference. In practice, this may not be feasible using existing implementation techniques. The rules above are a pragmatic compromise. The final clause above requires that certain common values always be boxed into indistinguishable objects. The implementation may cache these, lazily or eagerly.
For other values, this formulation disallows any assumptions about the identity of the boxed values on the programmer's part. This would allow (but not require) sharing of some or all of these references.
This ensures that in most common cases, the behavior will be the desired one, without imposing an undue performance penalty, especially on small devices. Less memory-limited implementations might, for example, cache all characters and shorts, as well as integers and longs in the range of -32K - +32K.
理想情况下,装箱给定的原始值 p 总是会产生相同的引用。实际上,使用现有的实现技术这可能是不可行的。上述规则是务实的妥协。上面的最后一条要求始终将某些常见值装入无法区分的对象中。实现可能会延迟或急切地缓存这些。
对于其他值,此公式不允许程序员对装箱值的身份进行任何假设。这将允许(但不要求)共享部分或所有这些引用。
这可确保在大多数常见情况下,行为将是所需的行为,而不会造成不应有的性能损失,尤其是在小型设备上。例如,内存限制较少的实现可能会缓存 -32K - +32K 范围内的所有字符和短整数,以及整数和长整数。
回答by Razib
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);
}
}
Output:
输出:
false
true
Yep the first output is produced for comparing reference; 'a' and 'b' - these are two different reference. In point 1, actually two references are created which is similar as -
是的,第一个输出是用于比较参考;'a' 和 'b' - 这是两个不同的引用。在第 1 点中,实际上创建了两个引用,类似于 -
Integer a = new Integer(1000);
Integer b = new Integer(1000);
The second output is produced because the JVMtries to save memory, when the Integerfalls in a range (from -128 to 127). At point 2 no new reference of type Integer is created for 'd'. Instead of creating a new object for the Integer type reference variable 'd', it only assigned with previously created object referenced by 'c'. All of these are done by JVM.
产生第二个输出是因为JVM当Integer落在一个范围内(从 -128 到 127)时,它会尝试节省内存。在第 2 点,没有为 'd' 创建新的 Integer 类型的引用。不是为 Integer 类型引用变量 'd' 创建一个新对象,它只分配给由 'c' 引用的先前创建的对象。所有这些都是由JVM.
These memory saving rules are not only for Integer. for memory saving purpose, two instances of the following wrapper objects (while created through boxing), will always be == where their primitive values are the same -
这些内存节省规则不仅适用于 Integer。为了节省内存,以下包装器对象的两个实例(通过装箱创建时)将始终是 ==,其中它们的原始值相同 -
- Boolean
- Byte
- Character from \u0000to
\u007f(7f is 127 in decimal) - Short and Integer from -128to 127
- 布尔值
- 字节
- 字符从\u0000到
\u007f(7f 是十进制的 127) - 从-128到127 的短整数和整数
回答by Adam Crume
Integer objects in some range (I think maybe -128 through 127) get cached and re-used. Integers outside that range get a new object each time.
某些范围内的整数对象(我认为可能是 -128 到 127)被缓存并重新使用。该范围之外的整数每次都会获得一个新对象。
回答by Avi
Yes, there is a strange autoboxing rule that kicks in when the values are in a certain range. When you assign a constant to an Object variable, nothing in the language definition says a new object mustbe created. It may reuse an existing object from cache.
是的,当值在某个范围内时,会出现一个奇怪的自动装箱规则。当您将常量分配给 Object 变量时,语言定义中没有任何内容表明必须创建新对象。它可以重用缓存中的现有对象。
In fact, the JVM will usually store a cache of small Integers for this purpose, as well as values such as Boolean.TRUE and Boolean.FALSE.
事实上,JVM 通常会为此目的存储小整数的缓存,以及诸如 Boolean.TRUE 和 Boolean.FALSE 之类的值。
回答by AmirHd
That is an interesting point. In the book Effective Javasuggests always to override equals for your own classes. Also that, to check equality for two object instances of a java class always use the equals method.
这是一个有趣的观点。在Effective Java一书中,建议始终为您自己的类覆盖 equals。此外,要检查 java 类的两个对象实例的相等性,请始终使用 equals 方法。
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));
}
}
returns:
返回:
true
true
回答by Omnifarious
My guess is that Java keeps a cache of small integers that are already 'boxed' because they are so very common and it saves a heck of a lot of time to re-use an existing object than to create a new one.
我的猜测是 Java 保留了一个已经“装箱”的小整数的缓存,因为它们非常常见,并且与创建新对象相比,重用现有对象可以节省大量时间。
回答by marvin
In Java the boxing works in the range between -128 and 127 for an Integer. When you are using numbers in this range you can compare it with the == operator. For Integer objects outside the range you have to use equals.
在 Java 中,对于整数,装箱的范围在 -128 到 127 之间。当您使用此范围内的数字时,您可以将其与 == 运算符进行比较。对于超出范围的 Integer 对象,您必须使用 equals。
回答by Naresh Joshi
Direct assignment of an int literal to an Integer reference is an example of auto-boxing, where the literal value to object conversion code is handled by the compiler.
将 int 文字直接分配给 Integer 引用是自动装箱的一个示例,其中文字值到对象的转换代码由编译器处理。
So during compilation phase compiler converts Integer a = 1000, b = 1000;to Integer a = Integer.valueOf(1000), b = Integer.valueOf(1000);.
所以在编译阶段编译器转换Integer a = 1000, b = 1000;为Integer a = Integer.valueOf(1000), b = Integer.valueOf(1000);.
So it is Integer.valueOf()method which actually gives us the integer objects, and if we look at the source code of Integer.valueOf()method we can clearly see the method caches integer objects in the range -128 to 127 (inclusive).
所以实际上是Integer.valueOf()方法给了我们整数对象,如果我们查看Integer.valueOf()方法的源代码,我们可以清楚地看到该方法缓存了-128到127(含)范围内的整数对象。
/**
*
* 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);
}
So instead of creating and returning new integer objects, Integer.valueOf()the method returns Integer objects from the internal IntegerCacheif the passed int literal is greater than -128 and less than 127.
因此,如果传递的 int 文字大于 -128 且小于 127 ,则Integer.valueOf()该方法不会创建和返回新的整数对象,而是从内部返回 Integer 对象IntegerCache。
Java caches these integer objects because this range of integers gets used a lot in day to day programming which indirectly saves some memory.
Java 缓存这些整数对象,因为这个整数范围在日常编程中被大量使用,这间接地节省了一些内存。
The cache is initialized on the first usage when the class gets loaded into memory because of the static block. The max range of the cache can be controlled by the -XX:AutoBoxCacheMaxJVM option.
由于静态块,当类被加载到内存中时,缓存在第一次使用时初始化。缓存的最大范围可以由-XX:AutoBoxCacheMaxJVM 选项控制。
This caching behaviour is not applicable for Integer objects only, similar to Integer.IntegerCache we also have ByteCache, ShortCache, LongCache, CharacterCachefor Byte, Short, Long, Characterrespectively.
对于整数对象只,类似于Integer.IntegerCache我们也有这缓存行为是不适用ByteCache, ShortCache, LongCache, CharacterCache的Byte, Short, Long, Character分别。
You can read more on my article Java Integer Cache - Why Integer.valueOf(127) == Integer.valueOf(127) Is True.
您可以在我的文章Java Integer Cache - Why Integer.valueOf(127) == Integer.valueOf(127) Is True 中阅读更多内容。
回答by Rahul Maurya
In Java 5, a new feature was introduced to save the memory and improve performance for Integer type objects handlings. Integer objects are cached internally and reused via the same referenced objects.
在 Java 5 中,引入了一个新特性来节省内存并提高整数类型对象处理的性能。整数对象在内部缓存并通过相同的引用对象重用。
This is applicable for Integer values in range between –127 to +127 (Max Integer value).
This Integer caching works only on autoboxing. Integer objects will not be cached when they are built using the constructor.
这适用于范围在 –127 到 +127(最大整数值)之间的整数值。
此整数缓存仅适用于自动装箱。使用构造函数构建整数对象时,它们不会被缓存。
For more detail pls go through below Link:
有关更多详细信息,请通过以下链接:
回答by L Joey
If we check the source code of Integerobeject, we will find the source of valueOfmethod just like this:
如果我们查看Integerobeject的源代码,我们会发现valueOf方法的来源是这样的:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
which can explain why Integerobjects, which in the range from -128 (Integer.low) to 127 (Integer.high), are the same referenced objects during the autoboxing. And we can see there is a class IntegerCachetakes care of the Integercache array, which is a private static inner class of Integerclass.
这可以解释为什么在自动装箱期间Integer从 -128 ( Integer.low) 到 127 ( Integer.high) 范围内的对象是相同的引用对象。我们可以看到有一个类IntegerCache负责Integer缓存数组,它是类的私有静态内部Integer类。
There is another interesting example may help us understand this weird situation:
还有一个有趣的例子可以帮助我们理解这种奇怪的情况:
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
}

