为什么(i <= j && j <= i && i!= j)评估为TRUE?


104

我已经编写了一段无限循环运行的Java代码。

下面是代码:

public class TestProgram {
    public static void main(String[] args){
        Integer i = new Integer(0);
        Integer j = new Integer(0);

        while(i<=j && j<=i && i!=j){
            System.out.println(i);
        }
    }
}

在上面的代码中,虽然看到了while循环中的条件,但起初看起来该程序不会进入while循环中。但实际上,这是一个无限循环,并不断显示该值。

这是怎么回事


8
简单的答案是i<=j && j<=i && i!=j这种情况总是评估为真。只要拿出一张纸,评估一下你就会抓起来:)
Pradeep Simha 2013年

4
您创建整数的方式不正确。使用'的compareTo'
nachokk

7
如果您从不更改ij,则您希望循环何时终止?
Fred Larson 2013年

33
@PradeepSimha对于简单的int值,这将始终产生false。从i<=jj<=i你可以得出结论,即i == j,这与上一届。因此,整个表达式的计算结果为false,而不会输入while。关键是这里的对象标识!
西尔科(Sirko)2013年

4
顺便说一句,这是《 Java Puzzlers:Traps,Pitfalls和Corner Cases》一书中的难题32。
Cyanfish

Answers:


188
  • i <= j被评估true的,因为自动拆箱发生了INT比较,那么这两个ij保持默认值0

  • j <= itrue由于上述原因而被评估为。

  • i != j被评估为true,因为ij都是不同的对象。并且在比较对象时,不需要自动拆箱。

所有的条件都为真,并没有更改i,并j在循环,所以它是无限运行。


10
您能解释一下,为什么!=检查引用对象的内存索引,为什么<=检查Integer ?? ..的未装箱值。为什么这些运算符之间有这样的区别?
Punith Raj

41
@PunithRaj <&>运算符在基元上起作用,而不在对象上起作用,因此这些运算符会自动取消装箱。但是==和!=运算符也可以用于对象比较,因此此处无需拆箱,因此可以比较对象。
Juned Ahsan 2013年

14
啊,隐式装箱/拆箱的隐藏危险!
2013年

3
堆栈溢出应该只添加一个新标签,“自动拆箱是Java有史以来最大的错误”。:-)。除了Java Puzzler书籍的作者。用它来标记这些问题。
user949300

4
注意,Integer.valueOf(0) == Integer.valueOf(0)因为在这种情况下,返回相同的对象总是被判断为真(见IntegerCache grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/...
维塔利费德林

40

因为你在比较

  • 0 < = 0 (true) // unboxing

  • 0 > = 0 (true) // unboxing

  • reference != secondReference (true)在创建对象时,不是原始比较。因此计算结果为while(true) { // Never ending loop }


2
哦!隐藏的自动装箱龙...很好的解释。
HybrisHelp 2013年

17

整数对象是不同的。它与基本的int类型不同。

查看此答案:如何在Java中正确比较两个Integer?

i != j部分是正确的,您原以为是错误的。


虽然是正确的,但这并不重要,也不能回答问题。
2013年

6
@Kon:其实这就是答案。true由于自动装箱,条件#1和#2的计算结果为。如果不使用#3自动装箱,则会在对象(内存位置)级别进行比较。
主页

1

循环没有结束,因为您的条件为true(i!= j为true,因为有2个不同的对象,请改用Integer.valueOf),并且在循环内,值没有更改,因此您的条件永远保持为真。


1

整数对象是不同的。它与基本的int类型不同。所以你可以那样做。您所做的只是比较对象,当然结果是正确的。


1

我们首先要了解两种不同的情况,

情况1:

        Integer i = new Integer(10);
        Integer j = new Integer(10);

        System.out.println((i<=j && j<=i && i!=j));
        System.out.println(i!=j);

情况2:

        Integer i = 10;
        Integer j = 10;

        System.out.println((i<=j && j<=i && i==j));
        System.out.println(i==j);

两者都不同,因为

在情况1中:i!=j将是true因为两者都引用了堆中的两个不同对象,并且不能相同。但

在情况2中:i==jtrue因为这10个都是整数文字,并且Java维护pool for Integer literals都有value (-128 <= X <= 127)。因此,在这种情况下,10 <= 127的结果为true,因此两者都将引用同一对象。



0

该方案保留上显示相同的值i,因为你不是递增或递减任一值ij。for中的条件始终保持为true,因此它是一个无限循环。


我认为问题更多是关于i!=j令人惊讶地评估为真实的部分,而不是<=比较。
Soravux13年

0

整数a =新整数(0); 整数b =新的整数(0);

<=和> =比较将使用未装箱的值0,而!=将比较引用并由于它们是不同的对象而将成功。

即使这也将有效

整数a = 1000; 整数b = 1000;

但这不是:

整数a = 100; 整数b = 100;

原因是因为Integer在内部对-128到127之间的Integer对象使用了缓存,并从该缓存返回其覆盖范围的实例。我不确定,但我想您也可以在“ java.lang.Integer.IntegerCache.high”包中更改其最大值。

为了更好地理解URL,检查URL:https : //www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching


-3

您必须知道在&& this和this&中有一点不同,当您使用&&时,则当第一个条件为true时,它将检查第二个条件是否为false,然后不检查第三个条件,因为在&运算符中,如果一个条件为false,则所有如果使用||,则语句为假 然后,如果它看到true,则它在您的代码中返回true,因为i和j在第一个条件为true且第二个条件为true时,则在第三个条件中将为false,因为它们相等且在条件为false的情况下。


我不知道为什么我的答案会获得地雷的价值,因为我的答案是正确的,请先查看此链接的正确性,然后再获取我的答案之前,请阅读更多stackoverflow.com/questions/5564410/difference-between-and
sara Sodagari
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.