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。条件自体を変更せずに、最初のケースをスキップするには(つまり、条件をfalseにするにはどうすればよいですか)。


12
私はもっ​​と制限があるべきだと思います、さもなければそれはあまりにもオープンです。
フェルマーのリトルスチューデント

52
System.out.println("Gotcha!");コメントの代わりに簡単ですか?:)
stuXnet 2013

7
いいですね、それからdouble a = Double.NaNが最も短い答えであり、私の「ハックは単なるごまかしです;)
Christian Kuetbach

47
これはかわいいJava雑学ですが、インタビューの質問にすることを誰も検討しないことを望みます。就職の候補者を検討している人は、候補者がどれだけの雑学を蓄積しているかではなく、プログラミングを理解しているかどうかを把握するためにできる限り最善を尽くすべきです。Javaでの17年間のプログラミングでは、浮動小数点数をほとんど使用していませんが、NaN構成ははるかに少なく、==演算子でどのように動作するかはあまりわかりません...
arcy

8
@ user1158692私は個人的に、基本的な演算子がオーバーライドされているプログラムを個人的に嫌い、Javaで受け取ったコードが乱されていないことをうれしく思います(私は*をベクトルのクロス積およびドット積としてオーバーライドしたことを確認しました。 !Javaで1が呼び出されたのに対して腹立たしい、両方のベクトル乗算の種類があり.cross()、他方がある.dot()と混乱はありません。また起こることができない「==演算子をオーバーライドして、常にfalseを返す」ということは、プロのjavaは思われます。
リチャード・チンクル

回答:


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、の値xがNaNである場合に限ります。

...


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

63
えっと、これは質問どおり完全に答えます。
デイブニュートン

5
@AswinMurugesh正解ですが、この回答と同じように完全に文字通り質問をしている場合は、else完全に削除できます。これは、技術的に質問の条件に違反するものではありません。
arshajii 2013年

67
これが私の投票で2番目に高い回答であることを考えると、私が非常に面白いか、くだらないプログラマであるかを結論付けるかどうかはわかりません。
Jeroen Vannevel 2013年

5
@JeroenVannevel要件を考えると、これが最もKISS / YAGNI /適切な答えだと思います;)
イズカタ2013年

12
@jddsantaella:明らかにこれは後で編集されました。元の質問は、「どうすれば「大丈夫」を印刷できないのか」と述べています。
Jeroen Vannevel 2013年

147

Java言語仕様 NaNに等しいではありませんNaN

したがって、次のxように等しくなるようになった行NaNは、これを引き起こします。

double x=Math.sqrt(-1);

Java言語仕様から:

浮動小数点演算子は例外を生成しません(§11)。オーバーフローする演算は符号付き無限大を生成し、アンダーフローする演算は非正規化値または符号付きゼロを生成し、数学的に明確な結果を持たない演算はNaNを生成します。NaNをオペランドとするすべての数値演算は、結果としてNaNを生成します。すでに説明したように、NaNは順序付けされていないため、1つまたは2つのNaNを含む数値比較演算はfalseを返し、NaNを含む!=比較はtrueを返します(xがNaNの場合はx!= xを含む)。


@sᴜʀᴇsʜᴀᴛᴛᴀ公平に言えば、「コーディング規約」を見つけるのに忙しく、実際に質問に答えるのを忘れていました
Richard Tingle

これは、aがObjectまたはdoubleとして宣言されている場合にのみ有効です。
Christian Kuetbach、2013

1
@ChristianKuetbach確かに、反対の情報がない場合、コメントアウトされた行は何でもかまいません
Richard Tingle

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ラボの誰もがこのようなものを思いつくはずはありません(インストラクターを含む)。
William Gaul

28
@WilliamGaulほんと?マルチスレッディングで起こりうる問題を示す基本的な例の1つであり、このテーマが簡単であると考える人は決して責任を
負う

4
私はあなたの答えを読むまでこの問題についてさえ考えませんでした。これを私のメンタルツールキットに追加していただきありがとうございます:)
Behe

56

置き換えられた行は読み取ることができます。

double x = Double.NaN;

これにより、問題が出力されます。

Java言語仕様(JLS)は言う:

浮動小数点演算子は例外を生成しません(§11)。オーバーフローする演算は符号付き無限大を生成し、アンダーフローする演算は非正規化値または符号付きゼロを生成し、数学的に明確な結果を持たない演算はNaNを生成します。NaNをオペランドとするすべての数値演算は、結果としてNaNを生成します。すでに説明したように、NaNは順序付けされていないため、1つまたは2つのNaNを含む数値比較演算はfalseを返し、NaNを含む!=比較はtrueを返します(xがNaNの場合はx!= xを含む)。


または、aがStringとして宣言されている場合、コンパイルエラーが発生しますa = "Nope"; そのため、「a」のタイプを尋ねました
Christian Kuetbach

上記のコードは型に関する情報を提供しないため、aはまだ定義されていないと仮定しました。
Mex

あなたの答えは答えだと思います。それはなぞなぞ作成者の心にありました。しかし、ルールは明確ではありませんでした。2つだけルールが与えられた:1だけをコメントに沿って挿入し、2つのみが「ガッチャプリントアウトしましょう!。
クリスチャンKuetbach

謎の作者は、コードを{}で囲んで常に有効にできたかもしれません
Mex

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 2013

4
@Mex-確かに機能しますa != aが、別のスレッドによって変更された可能性があるため、元のキーポイントを十分に保持してさらに重要なポイントを示します。これはインタビューでポイントを獲得すると思います。
OldCurmudgeon 2013

これは実際にはかなり賢いですが、a比較のために最初のアクセスと2番目のアクセスの間にある最初のスレッドによって変更されることを "期待"して機能すると思います
Richard Tingle

4
あなたの疑いを再確認してください。重要なifステートメントの上に書いたすべての内容は、必要に応じて1行の恐ろしい行
Richard Tingle

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
絶対に素晴らしい!
Dariusz 2013年

25

簡単な解決策の1つは次のとおりです。

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

しかし、私はこのなぞなぞのすべてのルールを知りません...

:) 私はこれがチートであることを知っていますが、すべてのルールを知らなくても、これは質問に対する最も簡単な解決策です:)


1
1行で記述できます;)
Christian Kuetbach 2013

6
@ChristianKuetbachすべてのプログラムと同様に
Richard Tingle

2
@ChristianKuetbach公平に言えば、実際にそのようにプログラムしようとすると、コンパイラはコンピュータ上のすべてのファイルをすぐに削除する必要があります
Richard Tingle

1
なぜそんなに難しいのですか?if (System.out.println("Gotcha") && false)
アレクシス

3
エラー: 'void'タイプはここでは許可されませんif(System.out.println( "Gotcha")&& false)コードはコンパイルされません...
Christian Kuetbach

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");
        }
    }
}  

イデオネデモ


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");
        }
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.