Java变量如何与自身不同?


106

我想知道这个问题是否可以用Java解决(我是该语言的新手)。这是代码:

class Condition {
    // you can change in the main
    public static void main(String[] args) { 
        int x = 0;
        if (x == x) {
            System.out.println("Ok");
        } else {
            System.out.println("Not ok");
        }
    }
}

我在实验室中收到以下问题:如何在x == x不修改条件本身的情况下跳过第一种情况(即使条件为假)?


12
我相信应该有更多的限制,否则就太开放了。
费马小学生

52
它像System.out.println("Gotcha!");评论一样简单吗?:)
stuXnet

7
好,然后是double a = Double.NaN,是最短的答案,我的“ hack只是作弊;)
Christian Kuetbach 2013年

47
这是一个可爱的Java琐事,但我希望没有人会考虑将其作为面试问题。考虑应聘者的人们应该尽力而为,找出应聘者是否懂编程,而不是要积累多少琐事。在Java编程的17年中,我几乎没有使用过浮点数,更不用说NaN构造了,更不用说知道它如何使用==运算符了……
arcy 2013年

8
@ user1158692意见很重要,我个人讨厌任何覆盖了基本运算符的程序,并且很高兴我在Java中接收到的任何代码都没有被弄乱(我看到*被重写为矢量叉积点积,因为两者都是向量乘法;令人发指!而在Java中一个被调用.cross()而另一个在.dot()并且没有混淆,而且“重写==运算符并总是返回false”这一事实似乎在Java中也不会发生
Richard Tingle

Answers:


172

一种简单的方法是使用Float.NaN

float x = Float.NaN;  // <--

if (x == x) {
    System.out.println("Ok");
} else {
    System.out.println("Not ok");
}
不好

您可以使用进行相同的操作Double.NaN


根据JLS§15.21.1。数值相等算子==!=

浮点相等性测试是根据IEEE 754标准的规则执行的:

  • 如果任一操作数为NaN,则结果为==为,false但结果!=true

    确实,检验x!=xtrue当且仅当xNa 的值为NaN 时才进行。

...


157
int x = 0;
if (x == x) {
    System.out.println("Not ok");
} else {
    System.out.println("Ok");
}

63
嘿,这完全回答了所问的问题。
戴夫牛顿

5
@AswinMurugesh是的,但是如果我们像本答案那样从字面上完全回答问题,那么我们可以将其else全部删除。从技术上讲,这不会违反问题的条款。
arshajii

67
考虑到这是我投票得第二高的答案,我不确定是否得出结论说我很有趣还是一个cr脚的程序员。
Jeroen Vannevel

5
@JeroenVannevel给出了要求,我认为这是最
吻合

12
@jddsantaella:很显然,此后进行了编辑。最初的问题是“如何打印'不正常'”。
Jeroen Vannevel

147

Java语言规范 NaN不等于NaN

因此,任何x等于的行NaN都会导致此情况,例如

double x=Math.sqrt(-1);

从Java语言规范中:

浮点运算符不会产生任何异常(第11节)。溢出的操作将生成有符号无穷大,下溢的操作将生成非规范化的值或有符号的零,而在数学上没有确定结果的操作将生成NaN。将NaN作为操作数的所有数值运算都会产生NaN。如前所述,NaN是无序的,因此涉及一个或两个NaN的数值比较操作将返回false,而涉及NaN的任何!=比较都将返回true,包括x!= x(当x为NaN时)。


@sᴜʀᴇsʜᴀᴛᴛᴀ一个公平的观点,我忙于去寻找所说的“编码约定”,以至于我忘了实际回答这个问题
Richard Tingle

仅当a被声明为Object或double时才有效。
Christian Kuetbach 2013年

1
@ChristianKuetbach是的,在没有任何相反信息的情况下,我认为注释行可能是任何内容
Richard Tingle 2013年

2
甚至我被骗的答案都是正确的,并且符合规则。我仅在if语句之前进行了编辑,并且仅打印了“ Gotcha !。我敢肯定,这个答案并不是这个谜语的创建者所想到的答案。但是,这个谜语的定义不明确(大多数软件项目)
Christian Kuetbach 2013年

73

不知道这是否是一个选项,但是x从局部变量更改为字段将允许其他线程在if语句的左侧和右侧之间更改其值。

这是简短的演示:

class Test {

    static int x = 0;

    public static void main(String[] args) throws Exception {

        Thread t = new Thread(new Change());
        t.setDaemon(true);
        t.start();

        while (true) {
            if (x == x) {
                System.out.println("Ok");
            } else {
                System.out.println("Not ok");
                break;
            }
        }
    }
}

class Change implements Runnable {
    public void run() {
        while (true)
            Test.x++;
    }
}

输出:

⋮
Ok
Ok
Ok
Ok
Ok
Ok
Ok
Ok
Not ok

8
哈哈+1是努力的结果,但是,伙计…… 我的 Java实验室中的任何人都不可能想到这样的事情(包括讲师)。
威廉·高尔

28
@WilliamGaul真的吗?尽管我总是这样,但它始终是显示多线程可能出现问题的基本示例之一,并且为什么认为此主题很容易的人永远都不应该负责:)
Pshemo

4
在阅读您的回答之前,我什至没有考虑过这个问题。感谢您将其添加到我的心理工具包中:)
Behe

56

替换的行可以读取。

double x = Double.NaN;

这将导致陷阱被打印。

Java语言规范(JLS)说:

浮点运算符不会产生任何异常(第11节)。溢出的操作将生成有符号无穷大,下溢的操作将生成非规范化的值或有符号的零,而在数学上没有确定结果的操作将生成NaN。将NaN作为操作数的所有数值运算都会产生NaN。如前所述,NaN是无序的,因此涉及一个或两个NaN的数值比较操作将返回false,而涉及NaN的任何!=比较都将返回true,包括x!= x(当x为NaN时)。


如果a被声明为String,则导致编译错误a =“ Nope”; 这就是为什么我要求输入“ a”的原因
Christian Kuetbach 2013年

上面的代码没有提供有关类型的信息,因此我假设a尚未定义。
Mex

我认为您的答案就是答案,这就是谜题创作者的想法。但是规则不明确。只有两个规则均给予:1,只有在符合注释插入和2只得到一个“疑难杂症打印出来!
基督教Kuetbach

谜语作者可以通过将{}中的代码括起来来使始终有效
墨西哥

30

我设法从中得到一个Gotcha!

volatile Object a = new Object();

class Flipper implements Runnable {
  Object b = new Object();

  public void run() {
    while (true)  {
      Object olda = a;
      a = b;
      a = olda;
    }
  }

}

public void test() {
  new Thread(new Flipper()).start();

  boolean gotcha = false;
  while (!gotcha) {
    // I've added everything above this - I would therefore say still legal.
    if (a == a) {
      System.out.println("Not yet...");
    } else {
      System.out.println("Gotcha!");
      // Uncomment this line when testing or you'll never terminate.
      //gotcha = true;
    }
  }
}

1
这不仅仅是问题所要求的注释而已。
Mex

我已经尝试过类似的方法,但是我认为可以保证始终产生相同的结果,不是吗?
AndreDurao

4
@Mex-确实可以,但是它保留了足够多的原始内容,以证明有时a != a由于另一个线程更改了另一个关键点。我怀疑这会在面试中赢得积分。
OldCurmudgeon

不过,这实际上确实很聪明,我认为这是通过“跳变”来实现的,该a跳变由第一和第二访问之间的第一个线程进行更改以进行比较
Richard Tingle 2013年

4
怀疑者们;值得注意的是,if如有必要,您在关键声明上所写的一切都可以写在一个可怕的行中
Richard Tingle 2013年

25

有很多解决方案:

class A extends PrintStream {
    public A(PrintStream x) {super(x);}
    public void println(String x) {super.println("Not ok");}
    public static void main(String[] args) {
        System.setOut(new A(System.out));
        int x = 0;
        if (x == x) {
            System.out.println("Ok");
        } else {
            System.out.println("Not ok");
        }
    }
}

1
除非我缺少任何东西,否则super.println应该是“不好”,对吧?
2013年

@Izkata是的,没有重新检查所需的输出应该是什么。
Johannes Kuhn

2
绝对辉煌​​!
2013年

25

一种简单的解决方案是:

System.out.println("Gotcha!");if(false)
if( a == a ){
  System.out.println("Not yet...");
} else {
  System.out.println("Gotcha!");
}

但是我不知道这个谜语的所有规则...

:) 我知道这是个骗子,但是不知道所有规则,这是问题的最简单解决方法:)


1
可以写成一行;)
Christian Kuetbach 2013年

6
@ChristianKuetbach所有程序都可以
Richard Tingle

2
@ChristianKuetbach公平地说,如果您尝试进行真正的编程,则编译器应立即删除计算机上的所有文件
Richard Tingle 2013年

1
为什么要这么难?if (System.out.println("Gotcha") && false)
alexis

3
错误:此处不允许'void'类型if(System.out.println(“ Gotcha”)&& false)您的代码将无法编译...
Christian Kuetbach 2013年

11

System在与相同的程序包中创建自己的类Condition
在这种情况下,您的System课程将隐藏java.lang.System课程

class Condition
{
    static class System
    {
        static class out
        {
            static void println(String ignored)
            {
                java.lang.System.out.println("Not ok");
            }
        }
    }

    public static void main (String[] args) throws java.lang.Exception
    {
        int x = 0;
        if (x == x) 
        {
           System.out.println("Not ok");
        } 
        else 
        {
           System.out.println("Ok");
        }
    }
}  

Ideone演示


9

从另一个答案中使用相同的跳过/更改输出方法:

class Condition {
    public static void main(String[] args) {
        try {
            int x = 1 / 0;
            if (x == x) {
                System.out.println("Ok");
            } else {
                System.out.println("Not ok");
            }
        } catch (Exception e) {
            System.out.println("Not ok");
        }
    }
}
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.