我刚看到类似这样的代码:
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);
}
}
运行时,此代码块将打印出来:
false
true
我明白为什么第一个是 false
:因为这两个对象是独立的对象,所以 ==
比较参考文献。但我不明白,为什么第二句话又回来了 true
? 当一个整数的值在某个范围内时,有没有奇怪的自动装箱规则?这是怎么回事?
12条答案
按热度按时间qnzebej01#
我的猜测是java保留了一个已经被“装箱”的小整数的缓存,因为它们非常常见,而且重用现有对象比创建新对象节省了大量时间。
b4lqfgs42#
如果我们查一下
Integer
同学们,我们可以找到valueOf
方法如下:这就解释了原因
Integer
对象,范围为-128(Integer.low
)至127(Integer.high
),是自动装箱过程中相同的引用对象。我们可以看到有一个班级IntegerCache
这就解决了问题Integer
缓存数组,它是Integer
班级。另一个有趣的例子可能有助于理解这种奇怪的情况:
mnowg1ta3#
这是一个有趣的观点。在书中,effectivejava建议总是为自己的类重写equals。另外,要检查java类的两个对象示例的相等性,请始终使用equals方法。
退货:
kiz8lqtg4#
输出:
是的,第一个输出是为了比较参考而产生的;'“a”和“b”-这是两个不同的参考。在第1点中,实际上创建了两个类似于-
产生第二个输出是因为
JVM
尝试保存内存,当Integer
落在范围内(从-128到127)。在点2,没有为“d”创建integer类型的新引用。它没有为整型引用变量“d”创建新对象,而是只分配了“c”引用的先前创建的对象。所有这些都是由JVM
.这些内存节省规则不仅适用于整数。为了节省内存,以下 Package 器对象的两个示例(通过装箱创建时)将始终为==其中它们的原语值相同-
布尔值
字节
字符从\u0000到
\u007f
(7f是十进制的127)从-128到127的短整数
yqyhoc1h5#
将int文本直接赋值给整数引用是自动装箱的一个示例,其中文本值到对象的转换代码由编译器处理。
所以在编译阶段编译器会转换
Integer a = 1000, b = 1000;
至Integer a = Integer.valueOf(1000), b = Integer.valueOf(1000);
.的确如此
Integer.valueOf()
方法,如果我们看一下Integer.valueOf()
方法我们可以清楚地看到该方法缓存范围为-128到127(包含)的整数对象。因此,与其创建并返回新的整数对象,
Integer.valueOf()
该方法从内部IntegerCache
如果传递的int文本大于-128小于127。java缓存这些整数对象是因为这些整数在日常编程中被大量使用,这间接地节省了一些内存。
当类由于静态块而被加载到内存中时,缓存在第一次使用时被初始化。缓存的最大范围可以由
-XX:AutoBoxCacheMax
jvm选项。这种缓存行为不适用于integer对象,类似于integer.integercache
ByteCache, ShortCache, LongCache, CharacterCache
为了Byte, Short, Long, Character
分别。您可以阅读更多关于我的文章java integer cache-为什么integer.valueof(127)==integer.valueof(127)是真的。
col17t5w6#
在java中,装箱在-128到127之间的整数范围内工作。当您在这个范围内使用数字时,您可以将它与==运算符进行比较。对于范围之外的整数对象,必须使用等于。
cu6pst1q7#
班级
Integer
根据jls 5.1.7的要求,包含介于-128和127之间的值缓存。拳击转换。所以当你使用==
检查二的相等性Integer
在这个范围内,你得到相同的缓存值,如果你比较两个Integer
如果超出这个范围,就会得到两个不同的值。您可以通过更改jvm参数来增加缓存上限:
或
参见内部
IntegerCache
班级:hgqdbh6s8#
某些范围内的整数对象(我想可能是-128到127)会被缓存并重新使用。超出该范围的整数每次都会得到一个新对象。
jtw3ybtb9#
整数缓存是java版本5中引入的一项功能,主要用于:
节省内存空间
性能改进。
输出:
True
```Integer number1 = 128;
Integer number2 = 128;
System.out.println("number1 == number2" + (number1 == number2);
Integer object = 100;
Integer object = Integer.valueOf(100);
说明:
此方法将始终缓存-128到127(含)范围内的值,并且可能缓存此范围之外的其他值。
当需要-128到127范围内的值时,它每次都返回一个恒定的内存位置。但是,当我们需要大于127的值时
return new Integer(i);
每次初始化对象时返回一个新引用。此外,
==
java中的运算符用于比较两个内存引用,而不是值。Object1
位于1000,包含值6。Object2
位于1020处,包含值6。Object1 == Object2
是False
因为它们有不同的内存位置,但是包含相同的值。tyg4sfes10#
在Java5中,引入了一个新特性来节省内存并提高整数类型对象处理的性能。整数对象在内部缓存,并通过相同的引用对象重用。
这适用于-127到+127(最大整数值)之间的整数值。
此整数缓存仅适用于自动装箱。使用构造函数生成整数对象时,不会缓存它们。
更多详情请点击以下链接:
整数缓存详细信息
uajslkp611#
是的,有一个奇怪的自动装箱规则,当值在某个范围内时就会生效。为对象变量指定常量时,语言定义中没有说明必须创建新对象。它可以重用缓存中的现有对象。
实际上,jvm通常会为此存储一个小整数的缓存,以及boolean.true和boolean.false等值。
piok6c0g12#
这个
true
行实际上是由语言规范保证的。根据第5.1.7节:如果装箱的值p为true、false、一个字节、一个介于\u0000到\u007f之间的字符或一个介于-128到127之间的int或short数字,则让r1和r2为p的任意两个装箱转换的结果。通常情况下r1==r2。
讨论继续进行,建议虽然你的第二行输出是有保证的,但第一行不是(见下面引用的最后一段):
理想情况下,装箱一个给定的原语值p,总是会产生一个相同的引用。在实践中,使用现有的实现技术可能不可行。上述规则是一种务实的妥协。上面的最后一句要求某些公共值总是被装箱到不可区分的对象中。实现可以懒洋洋地或迫不及待地缓存这些。
对于其他值,此公式不允许程序员对装箱值的标识进行任何假设。这将允许(但不要求)共享部分或所有这些引用。
这确保了在大多数常见情况下,行为将是所需的行为,而不会造成不适当的性能损失,特别是在小型设备上。例如,内存有限的实现可能会缓存-32k-+32k范围内的所有字符和短字符,以及整数和长字符。