Weird Integer boxing in Java
我刚刚看到类似的代码:
1 2 3 4 5 6 7 8 9 10 11 |
运行时,此代码块将打印出:
1 2 | false true |
我理解为什么第一个对象是
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.
讨论还在继续,建议尽管第二行的输出是有保证的,但第一行没有(见下面最后一段引用):
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.
1 2 3 4 5 6 7 8 9 10 11 |
输出:
1 2 | false true |
是的,第一个输出是为了比较引用而产生的;‘A’和‘B’——这是两个不同的引用。在点1中,实际上创建了两个引用,类似于-
第二个输出是因为当
这些内存保存规则不仅适用于整数。为了节省内存,以下包装器对象的两个实例(通过装箱创建时)将始终为==其中它们的基元值相同-
- 布尔
- 字节
- 从u0000到
\u007f 的字符(7f为127,十进制) - 短整数从-128到127
某些范围内的整数对象(我认为可能是-128到127)被缓存并重新使用。超出该范围的整数每次都会得到一个新对象。
这是一个有趣的观点。在这本书中,有效的Java建议总是为自己的类重写相等。同样,为了检查Java类的两个对象实例的相等性,总是使用等值方法。
1 2 3 4 5 6 7 8 9 10 11 |
返回:
1 2 | true true |
是的,有一个奇怪的自动氧化规则,当值在某个范围内时就开始起作用。将常量赋给对象变量时,语言定义中的任何内容都不表示必须创建新对象。它可以重用缓存中的现有对象。
实际上,为了实现这个目的,JVM通常会存储一个小整数缓存,以及boolean.true和boolean.false等值。
在Java中,拳击在整数128到127之间的范围内工作。使用此范围内的数字时,可以将其与==运算符进行比较。对于超出范围的整数对象,必须使用equals。
我的猜测是Java保留了一个已经被装箱的小整数的缓存,因为它们非常普通,它节省了大量的时间来重用现有的对象,而不是创建一个新的对象。
将int文本直接赋值给整数引用是自动装箱的一个例子,在这个例子中,编译器处理对象转换代码的文本值。
因此,在编译阶段,编译器将
因此,实际上是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /** * * 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); } |
因此,如果传递的int文本大于-128且小于127,那么方法不是创建和返回新的整数对象,而是从内部
Java缓存这些整数对象,因为这个整数的范围在日常编程中被大量使用,间接地节省了一些内存。
当类由于静态块而被加载到内存中时,第一次使用时会初始化缓存。缓存的最大范围可以由
这种缓存行为不仅适用于整数对象,类似于integer.integercache,我们还分别为
你可以在我的文章中读更多的Java整数缓存——为什么整型值(127)=整数。
如果我们检查
1 2 3 4 5 |
这可以解释为什么
还有一个有趣的例子可以帮助我们理解这种奇怪的情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 } |
在Java 5中,引入了一个新的特性来保存内存并提高整数类型对象处理的性能。整数对象在内部缓存,并通过相同的引用对象重用。
这适用于-127到+127之间的整数值(最大整数值)。
这个整数缓存只在自动氧化上工作。整数对象将使用构造函数生成时不缓存。
欲了解更多详情,请浏览以下链接:
整数缓存详细信息