(a == 1 && a == 2 && a == 3)はJavaでtrueと評価できますか?


176

私たちはそれがJavaScriptでできることを知っています

しかし、以下の条件で「成功」メッセージをJavaで印刷することは可能ですか?

if (a==1 && a==2 && a==3) {
    System.out.println("Success");
}

誰かが提案しました:

int _a = 1;
int a  = 2;
int a_ = 3;
if (_a == 1 && a == 2 && a_ == 3) {
    System.out.println("Success");
}

しかし、これを行うことで、実際の変数を変更しています。他に方法はありますか?


5
&&は論理and演算子です。つまり、a値1、2、および3を同時に持つ必要がありますが、これは論理的に不可能です。答えはノー、不可能です。1、2、または3のいずれかの値がifあるかどうかを確認するステートメントを記述しますかa
BorisPavlović18年

16
全員への注意:この質問はJavascriptの同じ質問から来る可能性があります:stackoverflow.com/questions/48270127/…この場合、答えはyes
nos

28
@ArthurAttout重複ではなく、その質問はJavascriptではなくJavaです。
nos

13
変数名に空白を使用するものは、Javaでも機能します。ただし、これは基本的にを使用する_場合と同じですが、表示されない点が異なります。
tobias_k

8
@Seelenvirtuose True。ただしif(a==1 && a==2 && a==3)、同時に評価されるとは限りません。そして、これを使用して、Unicodeのトリックに頼ることなくこの作業を行うことができます。
Erwin Bolwidt

回答:


324

はい、変数aを揮発性として宣言すると、複数のスレッドでこれを達成するのは非常に簡単です。

1つのスレッドは常に変数aを1から3に変更し、別のスレッドは常にそれをテストしa == 1 && a == 2 && a == 3ます。これは、コンソールに「成功」​​の継続的なストリームを印刷するのに十分な頻度で発生します。

else {System.out.println("Failure");}句を追加すると、テストが成功するよりもはるかに頻繁に失敗することがわかります。)

実際には、a揮発性として宣言しなくても機能しますが、私のMacBookでは21回しか機能しません。なしvolatileでは、コンパイラーまたはHotSpotはステートメントをキャッシュaまたは置換できます。ほとんどの場合、HotSpotはしばらくしてから、の値をキャッシュするアセンブリ命令にコンパイルします。、「成功」を永遠に印刷し続けます。ifif (false)a volatile

public class VolatileRace {
    private volatile int a;

    public void start() {
        new Thread(this::test).start();
        new Thread(this::change).start();
    }

    public void test() {
        while (true) {
            if (a == 1 && a == 2 && a == 3) {
                System.out.println("Success");
            }
        }
    }

    public void change() {
        while (true) {
            for (int i = 1; i < 4; i++) {
                a = i;
            }
        }
    }

    public static void main(String[] args) {
        new VolatileRace().start();
    }
}

83
これは素晴らしい例です!潜在的に危険な並行処理の問題についてジュニア
開発者

6
なしvolatileではありそうにありませんが、原則として、これはvolatileキーワードなしでも発生する可能性があり、任意の回数発生する可能性がありますが、一方で、それが発生する保証はありませんvolatile。しかし、もちろん、実際に起こっていることは静かで印象的です...
ホルガー

5
@AlexPruss私の会社では後輩だけでなく、すべての開発者に対して行った(それが可能であることがわかった)、回答の失敗の87%成功
Eugene

3
@Holger True、どちらの保証もありません。両方のスレッドが別々のコアに割り当てられる典型的なマルチフルコアまたはマルチCPUアーキテクチャでは、それはで発生する可能性が非常に高いですvolatile。実装するvolatileために作成されたメモリバリアにより、スレッドの速度が低下し、短時間で同期して動作する可能性が高くなります。それは私が予想したよりもはるかに頻繁に起こります。それは非常にタイミングに敏感だが、私は大体見ること0.2%との評価の0.8%の間で(a == 1 && a == 2 && a == 3)復帰true
Erwin Bolwidt 2018年

4
これは、実際にコードを少し変更するだけでなく、実際にtrueを返す唯一の答えです。+1
アレハンドロ

85

素晴らしいコードゴルフの答えからの概念(およびコード)を使用して、Integer値をいじることができます。

この場合、通常intキャストされないsにキャストされたIntegersを等しくすることができます。

import java.lang.reflect.Field;

public class Test
{
    public static void main(String[] args) throws Exception
    {
        Class cache = Integer.class.getDeclaredClasses()[0];
        Field c = cache.getDeclaredField("cache");
        c.setAccessible(true);
        Integer[] array = (Integer[]) c.get(cache);
        // array[129] is 1
        array[130] = array[129]; // Set 2 to be 1
        array[131] = array[129]; // Set 3 to be 1

        Integer a = 1;
        if(a == (Integer)1 && a == (Integer)2 && a == (Integer)3)
            System.out.println("Success");
    }
}

残念ながら、Erwin Bolwidtのマルチスレッド回答 (これはIntegerキャストが必要なため)ほどエレガントではありませんが、それでもいくつかの楽しい悪戯が行われます。


とても興味深い。私は虐待をいじっていましたInteger。キャスティングは残念ですが、それでもクールです。
Michael

@マイケル私はキャストを取り除く方法を完全に理解することはできません。 a1/2/3に設定するとa == 1、は満足しますが、逆にはなりません
phflack

4
私は数日前にJS / Ruby / Pythonおよびでこの質問に回答しましたJava。私は見つけることができる最も醜いバージョンが使用していたa.equals(1) && a.equals(2) && a.equals(3)、その力12及び3としてautoboxedされるようにInteger、S。
Eric Duminil、2018年

あなたが何をした場合のため@EricDuminilつまり、楽しいうちのいくつかを取る可能性があるaとクラスでboolean equals(int i){return true;}
phflack 2018年

1
私が言ったように、それは最も醜くないですが、それでも最適ではありません。Integer a = 1;ラインの前に、それはまだ明らかだa本当に整数です。
Eric Duminil、2018年

52

、この質問の @aioobe(とアドバイスに対する)JavaクラスのCプリプロセッサを使用することを示唆しています。

それは非常に奇妙ですが、それが私の解決策です:

#define a evil++

public class Main {
    public static void main(String[] args) {
        int evil = 1;
        if (a==1 && a==2 && a==3)
            System.out.println("Success");
    }
}

次のコマンドを使用して実行すると、正確に 1つが出力されますSuccess

cpp -P src/Main.java Main.java && javac Main.java && java Main

6
この種のコードは、実際にコンパイルする前に検索と置換を介してコードを実行するような感じですが、ワークフローの一部として誰かがそのようなことをしているのを見ることは間違いありません
phflack

1
@phflack私はそれが好きです、おそらくこの質問はコードを読むときに仮定をすることの危険性を示すことについてです。a変数であると想定するのは簡単ですが、プリプロセッサを備えた言語の任意のコード部分にすることができます。
ケビン

2
Javaではありません。それは「Cプリプロセッサを通過した後のJava」という言語です。この回答で使用されている同様の抜け穴。(注:人手不足があるオフトピック今コードゴルフのために)
user202729

40

Erwin Bolwidtphflackのすばらしい回答のおかげで、このコードをtrueに評価することが可能であることはすでに知っているので、提示されているような状態に対処するときは、高いレベルの注意を払う必要があることを示したいと思います。質問では、時々、あなたが見るものはあなたがそれがあなたが思っているものと正確には違うかもしれません。

これは、このコードSuccess!がコンソールに出力されることを示すための私の試みです。私は少し不正をしたことは知っていますが、それでもここに表示するには良い場所だと思います。

このようなコードを記述する目的が何であれ、次の状況に対処する方法と、見た目が間違っていないとチェックする方法を理解することをお勧めします。

ラテン語の「a」とは異なる文字であるキリル文字「a」を使用しました。ifステートメント使用されている文字をここで検査できます

これは、変数の名前が異なるアルファベットから取得されるため機能します。それらは異なる識別子であり、それぞれ異なる値を持つ2つの異なる変数を作成します。

このコードを適切に機能させるには、文字エンコーディングを両方の文字をサポートするものに変更する必要があることに注意してください。たとえば、すべてのUnicodeエンコーディング(UTF-8、UTF-16(BEまたはLE))、UTF-32、さらにはUTF-7 )、またはWindows-1251、ISO 8859-5、KOI8-R(指摘してくれてありがとう-Thomas WellerPaŭloEbermann-):

public class A {
    public static void main(String[] args) {
        int а = 0;
        int a = 1;
        if == 0 && a == 1) {
            System.out.println("Success!");
        }
    }
}

(今後このような問題に対処する必要がなくなることを願っています。)


@Michaelよく見えないってどういう意味?携帯電話で書いたのですが、デスクトップ表示に切り替えても問題ありません。それが私の答えをより良くするなら、私はそれが今少し難しいと思うので、それを明確にしてください。
はPrzemyslaw Moskal

@マイケルありがとうございます。私は私が私の答えの最後に入院することは十分に:)であると考えた
はPrzemyslaw Moskal

うん@mohsenmadi、私は携帯電話で、ここでそれを確認することはできませんが、私は編集の前に、最後の文は、私の例では、異なる言語を使用することについてだったことをかなり確信している:P
はPrzemyslaw Moskal

なぜ█== 0はa == 1に似ているのですか?
トーマスウェラー

1
もっとつべこべ:(とにかく推奨されているが)あなたは、必ずしもUTF-8を必要としない、両方持っている任意の文字エンコーディングаおよびa限り、あなたはそれをコードする(あまりにも、コンパイラおよびおそらく)にあるもの、あなたのエディタを伝えるよう、作品を。すべてのUnicodeエンコーディングが機能し(UTF-8、UTF-16(BEまたはLEの場合)、UTF-32、さらにはUTF-7)、Windows-1251、ISO 8859-5、KOI8-Rなども同様です。
–PaŭloEbermann 2018

27

PowerMockのパワーを使用して、これに(別の方法で以前に投稿した揮発性のデータ競合アプローチに加えて)アプローチする方法があります。PowerMockでは、メソッドを他の実装に置き換えることができます。これを自動アンボックス化と組み合わせると、元の式(a == 1 && a == 2 && a == 3)を変更せずに真にすることができます。

@phflackの答えは、Integer.valueOf(...)呼び出しを使用するJavaのオートボクシングプロセスの変更に依存しています。以下のアプローチは、Integer.intValue()呼び出しを変更して自動アンボックス化を変更することに依存しています。

以下のアプローチの利点は、問題のOPによって指定された元のifステートメントが変更されずに使用されることです。これが最もエレガントだと思います。

import static org.powermock.api.support.membermodification.MemberMatcher.method;
import static org.powermock.api.support.membermodification.MemberModifier.replace;

import java.util.concurrent.atomic.AtomicInteger;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@PrepareForTest(Integer.class)
@RunWith(PowerMockRunner.class)
public class Ais123 {
    @Before
    public void before() {
        // "value" is just a place to store an incrementing integer
        AtomicInteger value = new AtomicInteger(1);
        replace(method(Integer.class, "intValue"))
            .with((proxy, method, args) -> value.getAndIncrement());
    }

    @Test
    public void test() {
        Integer a = 1;

        if (a == 1 && a == 2 && a == 3) {
            System.out.println("Success");
        } else {
            Assert.fail("(a == 1 && a == 2 && a == 3) != true, a = " + a.intValue());
        }
    }

}

Powermock は、内部/外部クラスのフィールドaccess$nnnを読み取るために使用されるメソッドのような合成メソッドを置き換えることができprivateますか?それはいくつかの他の興味深い変種(とでも作業できるようになるint...変数)
ホルガー

@ホルガー興味深いアイデア、私はあなたが何を意味するのかわかります。まだ動作していません-動作を停止させる原因が明確ではありません。
Erwin Bolwidt

本当に良かった、それが私がやろうとしていたことですが、静的メソッドを不変クラスから変更することは、バイトコードを操作しないと非常に難しいことがわかりました。私は間違っていたようですが、PowerMockのことは聞いたことがありません。ちなみに、phflackの答えはオートボクシングに依存していません。キャッシュされたIntegerのアドレスを変更します(==は実際には値ではなくIntegerオブジェクトのアドレスを比較しています)。
Asoub 2018年

2
@Asoubキャスト((Integer)2)はintをボックス化します。 リフレクションを詳しく見てみると、リフレクションを使用してボックス化を解除することは不可能のようですが、代わりにインストルメンテーション(またはこの回答のようにPowerMock)で
phflack

@Holger代替メソッドを登録できaccess$0、メソッドの存在が登録時にチェックされますが、おそらく合成メソッドをインターセプトしません。ただし、置換が呼び出されることはありません。
Erwin Bolwidt 2018年

17

これはこのJavaScriptの質問のフォローアップであるように思われるので、このトリックと同様のことがJavaでも機能することは注目に値します。

public class Q48383521 {
    public static void main(String[] args) {
        int a = 1;
        int 2 = 3;
        int a = 3;
        if(aᅠ==1 && a==ᅠ2 && a==3) {
            System.out.println("success");
        }
    }
}

イデオネ


ただし、これはUnicodeで実行できる最悪のことではないことに注意してください。有効な識別子の部分である空白文字または制御文字を使用したり、同じように見える別の文字を使用したりても、たとえばテキスト検索を行う場合など、異なる識別子が見つかる可能性があります。

しかし、このプログラム

public class Q48383521 {
    public static void main(String[] args) {
        int ä = 1;
        int ä = 2;
        if(ä == 1 && ä == 2) {
            System.out.println("success");
        }
    }
}

少なくともUnicodeの観点からは、同じ2つの識別子を使用します。彼らはただ同じ文字をエンコードするためにさまざまな方法を使用してä使用して、U+00E4U+0061 U+0308

イデオネ

したがって、使用しているツールによっては、見た目が同じであるだけでなく、Unicode対応のテキストツールでも違いが報告されず、検索時に常に両方が見つかる場合があります。ソースコードを他の人にコピーするときにさまざまな表現が失われ、「奇妙な動作」のヘルプを取得しようとすると、ヘルパーが再現できないという問題が発生する場合もあります。


3
ええと、この回答はユニコードの乱用を十分にカバーしていませんか?
Michael

2
int ᅠ2 = 3;それは意図的ですか?なぜなら、私はいたるところに非常に奇妙なコードを見ているからです
Ravi

1
@Michaelは正確にはそうではありません。その答えは2つの異なる文字(IDEがを検索するときに異なると見なすa)を使用することに関するものです。注意が私のコメント(数日)は、Javaの問題よりもさらに古いです...
ホルガー

2
違いはわかりません。どちらの答えも、ifステートメント内の3つの識別子が視覚的には似ているが、通常とは異なるUnicode文字を使用しているために技術的に異なるソリューションを提供しています。空白かキリル文字かは関係ありません。
Michael

2
@マイケルあなたはそれをそのように見るかもしれません、それはあなた次第です。先ほど述べたように、JavaScriptについて5日前に出された答えは、質問の履歴を考慮するだけでJavaにも当てはまることを述べたかったのです。はい、これは、リンクされたJavaScriptの質問を参照しない別の回答とは多少冗長です。とにかく、その間、私は回答を更新して、視覚的に類似した文字ではなく、同じ文字をエンコードするさまざまな方法で、「異常なUnicode文字」でさえないケースを追加しました。それは私が毎日使用しているキャラクターです
Holger

4

@Erwinのすばらしい答えに触発されて、私は同様の例を書きましたが、Java Stream APIを使用しています

そして興味深いのは、私のソリューションが機能することですが、非常にまれなケースです(just-in-timeコンパイラーがそのようなコードを最適化するため   )。

トリックはJIT、次のVMオプションを使用して最適化を無効にすることです:

-Djava.compiler=NONE

この状況では、成功事例の数が大幅に増加します。これがコードです:

class Race {
    private static int a;

    public static void main(String[] args) {
        IntStream.range(0, 100_000).parallel().forEach(i -> {
            a = 1;
            a = 2;
            a = 3;
            testValue();
        });
    }

    private static void testValue() {
        if (a == 1 && a == 2 && a == 3) {
            System.out.println("Success");
        }
    }
}

PS Parallelストリームは内部で使用ForkJoinPoolし、変数aは同期せずに複数のスレッド間で共有されるため、結果は非決定的です。


1

同様の行に沿っ、浮動小数点数(または倍精度浮動小数点数)を強制的にアンダーフロー(またはオーバーフロー)させ、多数による除算(または乗算)を実行します。

int a = 1;
if (a / Float.POSITIVE_INFINITY == 1 / Float.POSITIVE_INFINITY
        && a / Float.POSITIVE_INFINITY == 2 / Float.POSITIVE_INFINITY
        && a / Float.POSITIVE_INFINITY == 3 / Float.POSITIVE_INFINITY) {
    System.out.println("Success");
}

2
@PatrickRoberts-この特定の動作は、Java docsによる浮動小数点アンダーフローです。参照してください、このこのこのこのことを
Aloke、2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.