我刚刚看到类似的代码:
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
?当Integer的值在一定范围内时,是否会出现一些奇怪的自动装箱规则?这是怎么回事?
答案 0 :(得分:96)
true
行实际上由语言规范保证。来自section 5.1.7:
如果装箱的值p为真, false,一个字节,范围内的char \ u0000到\ u007f,或者是int或short 在-128和127之间的数字,然后让 r1和r2是任意两个的结果 p的拳击转换它始终是 r1 == r2。
的情况
讨论继续进行,建议虽然你的第二行输出是有保证的,但第一行不是(参见下面引用的最后一段):
理想情况下,装箱给定的原语 值p,总会产生一个 相同的参考。在实践中,这 使用现有可能不可行 实施技术。规则 以上是务实的妥协。该 上述最后条款要求 某些常见值总是被装箱 成为无法区分的对象。该 实施可能会缓慢地缓存这些 或热切地。
对于其他值,此配方 不允许任何关于。的假设 身上的盒装价值的身份 程序员的一部分。这样就可以了 (但不要求)分享一些或 所有这些参考文献。
这确保了最常见的 案件,行为将是 期望的,没有施加不适当的 性能惩罚,特别是 小型设备。内存限制较少 例如,实现可能 缓存所有字符和短片,如 以及整数和长期 范围为-32K - + 32K。
答案 1 :(得分:24)
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);
}
}
<强>输出:强>
false
true
是否生成第一个输出用于比较参考; &#39;一个&#39;和&#39; b&#39; - 这是两个不同的参考。在第1点中,实际创建了两个类似于 -
的引用Integer a = new Integer(1000);
Integer b = new Integer(1000);
产生第二个输出是因为当JVM
落在一个范围内(从-128到127)时Integer
试图节省内存。在第2点,没有为&#39; d&#39;创建类型为Integer的新引用。它不是为整数类型引用变量创建一个新对象,而是仅使用&#39; c&#39;引用的先前创建的对象进行分配。所有这些都是由JVM
完成的。
这些内存保存规则不仅适用于Integer。为了节省内存,以下包装器对象的两个实例(通过装箱创建)将始终为==其原始值相同 -
\u007f
的字符(7f为十进制127)答案 2 :(得分:8)
某些范围内的整数对象(我认为可能是-128到127)会被缓存并重新使用。该范围之外的整数每次都会获得一个新对象。
答案 3 :(得分:4)
是的,当值在某个范围内时,会出现一个奇怪的自动装箱规则。为Object变量赋值时,语言定义中没有任何内容表示必须创建新对象。它可以重用缓存中的现有对象。
实际上,JVM通常会为此目的存储一个小整数缓存,以及Boolean.TRUE和Boolean.FALSE等值。
答案 4 :(得分:4)
这是一个有趣的观点。 在书中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));
}
}
返回:
true
true
答案 5 :(得分:3)
我的猜测是Java保留了已经“装箱”的小整数缓存,因为它们非常常见,它可以节省大量时间来重用现有对象,而不是创建一个新对象。
答案 6 :(得分:3)
在Java中,对于整数,拳击在-128到127之间的范围内工作。当您使用此范围内的数字时,可以将其与==运算符进行比较。对于范围之外的整数对象,您必须使用等于。
答案 7 :(得分:1)
将int常量直接分配给Integer引用是自动装箱的示例,其中,由编译器处理到对象转换代码的常量值。
因此,在编译阶段,编译器会将Integer a = 1000, b = 1000;
转换为Integer a = Integer.valueOf(1000), b = Integer.valueOf(1000);
。
实际上是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);
}
因此,如果传递的int文字大于-128且小于127,则Integer.valueOf()
会从内部IntegerCache
返回Integer对象,而不是创建和返回新的整数对象。
Java会缓存这些整数对象,因为这种整数范围在日常编程中被大量使用,从而间接节省了一些内存。
由于静态块而将类加载到内存时,第一次使用时会初始化缓存。缓存的最大范围可以由-XX:AutoBoxCacheMax
JVM选项控制。
与Integer类似,此缓存行为仅适用于Integer对象。IntegerCache我们分别为ByteCache, ShortCache, LongCache, CharacterCache
有Byte, Short, Long, Character
。
您可以阅读我的文章Java Integer Cache - Why Integer.valueOf(127) == Integer.valueOf(127) Is True的更多信息。
答案 8 :(得分:0)
在Java 5中,引入了一项新功能来保存内存并提高Integer类型对象处理的性能。整数对象在内部缓存,并通过相同的引用对象重用。
这适用于介于-127到+127之间的整数值 (最大整数值)。
此整数缓存仅适用于自动装箱。整数对象会 使用构造函数构建时不要缓存。
有关详细信息,请参阅下面的链接:
答案 9 :(得分:0)
如果我们检查Integer
obeject的源代码,我们会找到valueOf
方法的来源,如下所示:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
这可以解释为什么{-1}}对象(在-128(Integer
)到127(Integer.low
)范围内,在自动装箱期间是相同的引用对象。我们可以看到有一个类Integer.high
负责IntegerCache
缓存数组,它是Integer
类的私有静态内部类。
另一个有趣的例子可以帮助我们理解这种奇怪的情况:
Integer
答案 10 :(得分:0)
类Integer
包含-128和127之间的值的高速缓存,这是JLS 5.1.7. Boxing Conversion所要求的。因此,当您使用==
检查此范围内两个Integer
的相等性时,您将获得相同的缓存值,并且如果您比较此范围之外的两个Integer
,则您得到两个不同的值。
您可以通过更改JVM参数来增加缓存上限:
-XX:AutoBoxCacheMax=<cache_max_value>
或
-Djava.lang.Integer.IntegerCache.high=<cache_max_value>
请参阅内部IntegerCache
类:
/**
* Cache to support the object identity semantics of autoboxing for values
* between -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
答案 11 :(得分:0)
Integer Cache是Java版本5中主要针对的功能:
Integer number1 = 127;
Integer number2 = 127;
System.out.println("number1 == number2" + (number1 == number2);
输出: True
Integer number1 = 128;
Integer number2 = 128;
System.out.println("number1 == number2" + (number1 == number2);
输出: False
如何?
实际上,当我们将值分配给Integer对象时,它会在引擎盖后面进行自动升级。
Integer object = 100;
实际上是在调用 Integer.valueOf()函数
Integer object = Integer.valueOf(100);
valueOf(int)
的实质内容
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
说明:
此方法将始终缓存-128至127范围内的值, 包含在内,并且可能会缓存该范围之外的其他值。
当需要在-128到127范围内的值时,每次都会返回一个恒定的存储位置。 但是,当我们需要大于127的值时
return new Integer(i);
每次启动对象时都会返回一个新引用。
Java中的 ==
运算符比较两个内存引用而不是值。
Object1
位于1000,包含值6。
Object2
位于1020,包含值6。
Object1 == Object2
是False
,因为它们包含相同的值,但它们具有不同的存储位置。