当比较Java中的Integer包装器时,为什么128 == 128 false但127 == 127为真?

vip*_* k. 160 java comparison integer pass-by-reference pass-by-value

class D {
    public static void main(String args[]) {
        Integer b2=128;
        Integer b3=128;
        System.out.println(b2==b3);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

false
Run Code Online (Sandbox Code Playgroud)
class D {
    public static void main(String args[]) {
        Integer b2=127;
        Integer b3=127;
        System.out.println(b2==b3);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

true
Run Code Online (Sandbox Code Playgroud)

注意:-128到127之间的数字为真.

And*_*son 207

当您在Java中编译数字文字并将其分配给Integer(大写I)时,编译器会发出:

Integer b2 =Integer.valueOf(127)
Run Code Online (Sandbox Code Playgroud)

使用自动装箱时也会生成此行代码.

valueOf 实现使某些数字"合并",并为小于128的值返回相同的实例.

从java 1.6源代码,第621行:

public static Integer valueOf(int i) {
    if(i >= -128 && i <= IntegerCache.high)
        return IntegerCache.cache[i + 128];
    else
        return new Integer(i);
}
Run Code Online (Sandbox Code Playgroud)

high可以使用系统属性将值配置为其他值.

-Djava.lang.Integer.IntegerCache.high = 999

如果您使用该系统属性运行程序,它将输出true!

明显的结论是:永远不要依赖两个相同的引用,总是将它们与.equals()方法进行比较.

因此,b2.equals(b3)对于所有逻辑上相等的b2,b3值,将打印为true.

请注意,出于性能原因,Integer缓存不存在,而是符合JLS,第5.1.7节 ; 必须为-128到127(包括端点)的值给出对象标识.

整数#valueOf(int)也记录了这种行为:

通过缓存频繁请求的值,此方法可能会显着提高空间和时间性能.此方法将始终缓存-128到127(包括端点)范围内的值,并可以缓存此范围之外的其他值.

  • 不,这是错的.new Integer(1)== new无论jvm如何,整数(1)都是假的.AFAIK没有编译器会欺骗"new"关键字.它必须始终实例化一个新对象. (11认同)
  • @Holger 有趣的一点。但是技术上可以用自定义实现替换 JDK 中的 Integer 类......(不要问为什么有人会那么疯狂) - 那么它可能会产生不允许优化的副作用 (2认同)
  • @AndreasPetersson 当然。“编译器”是指 JIT 编译器,它确实知道实际的实现类,并且只有在构造函数没有副作用的情况下才能进行优化。或者优化表达式以仅重现副作用,然后使用 `false`。实际上,这在今天可能已经发生,作为应用逃逸分析和标量替换的副作用。 (2认同)

Mic*_*mlk 22

自动装箱缓存-128到127.这在JLS(5.1.7)中指定.

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

处理对象时要记住的一个简单规则是 - 如果要检查两个对象是否"相等",请使用.equals,当您想要查看它们是否指向同一个实例时,请使用==.

  • 注意:JLS 在 Java 9 中发生了变化。现在仅保证*编译时常量表达式*;请参阅已接受答案的更新。 (2认同)

chr*_*ney 8

使用原始数据类型int,在两种情况下都会产生预期的输出.

但是,由于您使用的是Integer对象,因此==运算符具有不同的含义.

在对象的上下文中,==检查变量是否引用相同的对象引用.

要比较对象的值,您应该使用equals()方法Eg

 b2.equals(b1)
Run Code Online (Sandbox Code Playgroud)

这将指示b2是否小于b1,大于或等于(查看API以获取详细信息)


dis*_*ame 7

它与Java相关的内存优化.

为了节省内存,Java'重用'所有值包含在以下范围内的包装器对象:

所有布尔值(true和false)

所有字节值

从\ u0000到\ u007f的所有字符值(即十进制中的0到127)

所有短和整数值从-128到127.

注意:

  • 如果使用new Boolean(value)创建Boolean; 你将永远得到新的对象

  • 如果使用new String(value)创建String; 你将永远得到新的对象

  • 如果用新的Integer(value)创建Integer; 你将永远得到新的对象

等等