Java中奇怪的整数拳击

Joe*_*oel 108 java autoboxing

我刚刚看到类似这样的代码:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

运行时,这段代码将打印出来:

false
true
Run Code Online (Sandbox Code Playgroud)

我理解为什么第一个是false:因为这两个对象是单独的对象,所以==比较引用.但我无法弄清楚,为什么第二个声明会回来true?当Integer的值在一定范围内时,是否会出现一些奇怪的自动装箱规则?这里发生了什么?

Jon*_*eet 97

true行实际上由语言规范保证.从5.1.7节:

如果被装箱的值p为true,false,一个字节,范围为\ u0000到\ u007f的char,或者介于-128和127之间的int或短号,则让r1和r2为任意两个装箱转换的结果p.始终是r1 == r2的情况.

讨论继续进行,表明尽管你的第二行产出是有保证的,但第一行却没有(参见下面引用的最后一段):

理想情况下,装箱给定的原始值p将始终产生相同的参考.实际上,使用现有的实现技术可能不可行.上述规则是一种务实的妥协.上面的最后一个条款要求将某些常见值装入无法区分的对象中.实现可以懒惰地或急切地缓存这些.

对于其他值,此公式不允许对程序员的盒装值的身份进行任何假设.这将允许(但不要求)共享部分或全部这些引用.

这确保了在大多数常见情况下,行为将是期望的行为,而不会造成过度的性能损失,尤其是在小型设备上.例如,较少内存限制的实现可以缓存所有字符和短路,以及-32K - + 32K范围内的整数和长整数.

  • 值得注意的是,autoboxing实际上只是用于调用box类的`valueOf`方法的语法糖(如[`Integer.valueOf(int)`](http://java.sun.com/javase/6 /docs/api/java/lang/Integer.html#valueOf%28int%29)).有趣的是,JLS定义了确切的拆箱去除 - 使用`intValue()`等 - 而不是拳击desugaring. (17认同)

Raz*_*zib 28

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);
   }
}
Run Code Online (Sandbox Code Playgroud)

输出:

false
true
Run Code Online (Sandbox Code Playgroud)

是的,第一个输出产生用于比较参考; 'a'和'b' - 这是两个不同的参考.在第1点,实际上创建了两个类似于 - 的引用

Integer a = new Integer(1000);
Integer b = new Integer(1000);
Run Code Online (Sandbox Code Playgroud)

产生第二个输出是因为JVM试图Integer在一个范围内(从-128到127)下降时节省内存.在第2点,没有为'd'创建类型为Integer的新引用.它不是为Integer类型引用变量'd'创建新对象,而是仅使用'c'引用的先前创建的对象进行分配.所有这些都是通过JVM.

这些内存保存规则不仅适用于Integer.为了节省内存,以下包装器对象的两个实例(通过装箱创建)将始终为==,其原始值相同 -

  • 布尔
  • 字节
  • 字符从\ u0000\u007f(7f是十进制的127)
  • -128127的短整数

  • “长”也具有与“整数”相同范围的缓存。 (2认同)

Zah*_*han 12

整数缓存是 Java 版本 5 中引入的一项功能,主要用于:

  1. 节省内存空间
  2. 性能提高。
Integer number1 = 127;
Integer number2 = 127;

System.out.println("number1 == number2" + (number1 == number2); 
Run Code Online (Sandbox Code Playgroud)

输出: True


Integer number1 = 128;
Integer number2 = 128;

System.out.println("number1 == number2" + (number1 == number2);
Run Code Online (Sandbox Code Playgroud)

输出: False

如何?

实际上,当我们为 Integer 对象赋值时,它会在幕后进行自动提升。

Integer object = 100;
Run Code Online (Sandbox Code Playgroud)

实际上是调用Integer.valueOf()函数

Integer object = Integer.valueOf(100);
Run Code Online (Sandbox Code Playgroud)

的具体细节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);
    }
Run Code Online (Sandbox Code Playgroud)

描述:

此方法将始终缓存 -128 到 127(含)范围内的值,并且可能缓存此范围之外的其他值。

当需要 -128 到 127 范围内的值时,它每次都会返回一个恒定的内存位置。然而,当我们需要一个大于 127 的值时

return new Integer(i);

每次我们启动一个对象时都会返回一个新的引用。


此外,==Java 中的运算符用于比较两个内存引用而不是值。

Object1位于 1000 处,包含值 6。
Object2位于 1020 处,包含值 6。

Object1 == Object2因为False它们虽然包含相同的值,但具有不同的内存位置。


Ada*_*ume 8

某些范围内的整数对象(我认为可能是-128到127)会被缓存并重新使用.该范围之外的整数每次都会获得一个新对象.


Avi*_*Avi 5

是的,当值在一定范围内时,会出现一个奇怪的自动装箱规则。将常量分配给Object变量时,语言定义中没有任何内容表明必须创建一个新对象。它可以重用缓存中的现有对象。

实际上,JVM通常会为此目的存储小型Integer的缓存以及诸如Boolean.TRUE和Boolean.FALSE的值。