【问题标题】:Why does (i<=j && j<=i && i!=j) evaluate to TRUE?为什么 (i<=j && j<=i && i!=j) 评估为 TRUE?
【发布时间】:2013-09-14 17:43:04
【问题描述】:

我写了一段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 循环。但实际上它是一个无限循环并不断打印值。

这里发生了什么?

【问题讨论】:

  • 简单的答案是i&lt;=j &amp;&amp; j&lt;=i &amp;&amp; i!=j 这个条件总是为真。只需拿一张纸,评估一下你就能抓住它:)
  • 您创建整数的方式不正确。使用“比较”
  • 如果您从不更改ij,您希望循环何时终止?
  • @PradeepSimha 对于简单的 int 值,这总是会产生 false。从i&lt;=jj&lt;=i 你可以得出结论,i == j 与上一个术语相矛盾。因此,整个表达式的计算结果为 false,并且不会输入 while。关键是这里的对象标识!
  • 顺便说一句,这是 Java Puzzlers: Traps, Pitfalls, and Corner Cases 一书中的谜题 32。

标签: java


【解决方案1】:
  • i &lt;= j 被评估为 true,因为自动拆箱发生在 int 比较,然后ij 都保持默认值0

  • 由于上述原因,j &lt;= i 被评估为 true

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

所有条件都为真,并且您没有在循环中更改ij,因此它无限运行。

【讨论】:

  • 你能解释一下,为什么 != 是检查引用对象的内存索引,而
  • @PunithRaj 运算符作用于原语而不是对象,因此这些运算符会自动拆箱。但是 == 和 != 运算符也可以用于对象比较,所以这里不需要拆箱,因此对象是比较的。
  • 啊,隐式装箱/拆箱的隐患!!
  • Stack Overflow 应该只添加一个新标签,“自动拆箱是 Java 有史以来最大的错误”。 :-)。 Java Puzzler 书籍的作者除外。用它来标记这些问题。
  • 请注意,Integer.valueOf(0) == Integer.valueOf(0) 始终被评估为 true,因为在这种情况下,返回的是相同的对象(请参阅 IntegerCache grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
【解决方案2】:

因为你在比较

  • 0 &lt; = 0 (true) // unboxing

  • 0 &gt; = 0 (true) // unboxing

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

【讨论】:

  • 哦!自动拆箱的隐藏龙...很好的解释。
【解决方案3】:

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

看到这个答案:How to properly compare two Integers in Java?

i != j 部分为真,而您预期为假。

【讨论】:

  • 虽然是真的,但这并不重要,也没有回答问题。
  • @Kon:事实上这就是答案。由于自动装箱,条件 #1 和 #2 评估为 true。如果 #3 自动装箱不适用,并且比较发生在对象(内存位置)级别。
【解决方案4】:

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

案例一:

        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==j 将是 true,因为这 10 都是整数文字,Java 维护 pool for Integer literals,其值为 (-128 &lt;= X &lt;= 127)。所以,在这种情况下,10

【讨论】:

    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

      也许原因是'i'和'j'都是对象,对象比较和对象引用比较是不一样的。请考虑使用 !i.equals(j) 而不是 i!=j

      【讨论】:

        【解决方案7】:

        整数对象不同。它不同于基本的 int 类型。 所以你可以这样做。你所做的只是比较对象,结果当然是真的。

        【讨论】:

          【解决方案8】:

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

          = 比较将使用未装箱的值 0,而 != 将比较引用并成功,因为它们是不同的对象。

          即使这样也可以,我,e

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

          但这没有:

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

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

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

          【讨论】:

            【解决方案9】:

            程序继续显示i 的相同值,因为您没有增加或减少ij 的值。 for 中的条件始终保持为真,因此它是一个无限循环。

            【讨论】:

            • 我认为问题更多是关于 i!=j 部分,它出人意料地评估为真,而不是 &lt;= 比较。
            【解决方案10】:

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

            【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-09-20
            • 2021-02-28
            • 2018-09-06
            • 1970-01-01
            • 1970-01-01
            • 2021-04-09
            • 1970-01-01
            • 2019-04-19
            相关资源
            最近更新 更多