[java] Java에서 (a == 1 && a == 2 && a == 3)을 true로 평가할 수 있습니까?

우리는 그것이 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");
}

그러나 이렇게하면 실제 변수가 변경됩니다. 다른 방법이 있습니까?



답변

예, 변수 a를 휘발성으로 선언하면 여러 스레드 로이 작업을 수행하는 것이 매우 쉽습니다 .

하나의 스레드는 변수 a를 1에서 3으로 지속적으로 변경하고 다른 스레드는 지속적으로 테스트합니다 a == 1 && a == 2 && a == 3. 콘솔에 연속적인 “성공”스트림을 인쇄하기에 충분한 경우가 종종 있습니다.

( else {System.out.println("Failure");}구문 을 추가 하면 테스트가 성공보다 훨씬 자주 실패한다는 것을 알 수 있습니다.)

실제로, 그것은 a휘발성으로 선언하지 않고 MacBook에서 21 번만 작동합니다 . 이 없으면 volatile컴파일러 또는 HotSpot a에서 if명령문 을 캐시 하거나 대체 할 수 if (false)있습니다. HotSpot은 잠시 후 시작하여 값을 캐시하는 어셈블리 명령어로 컴파일합니다 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();
    }
}


답변

A로부터 개념 (코드)를 사용하여 화려한 코드 골프 대답을 , Integer값이 엉망이 될 수있다.

이 경우 일반적으로 그렇지 않을 때 ints로 캐스팅 된 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주물 이 필요하기 때문에)만큼 우아 하지는 않지만 여전히 재미있는 재미가 있습니다.


답변

에서 이 질문 @aioobe는 (에 대한 및 조언) 자바 클래스 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");
    }
}

다음 명령을 사용하여 실행하면 정확히 하나 를 출력 합니다Success .

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


답변

우리가 이미 알고 있듯이 것이 가능 의 큰 응답에 대한 진정한 감사로 평가이 코드를 만들기 위해 어윈 Bolwidtphflack을 것과 같은 모양이되게하는 것이, 나는 조건을 처리 할 때주의의 높은 수준을 유지해야한다는 것을 보여주고 싶었다 때로는 당신이 보는 것이 정확히 당신이 생각하는 것이 아닐 수도 있습니다.

이것은이 코드 Success!가 콘솔에 인쇄된다는 것을 보여주기위한 나의 시도 입니다. 나는 속임수를 쓴다는 것을 알고 있지만 여전히 여기에 그것을 제시하기에 좋은 곳이라고 생각합니다.

이와 같은 코드 작성의 목적이 무엇이든 관계없이 다음 상황을 처리하는 방법과 자신이 생각하는 내용이 잘못되었는지 확인하는 방법을 아는 것이 좋습니다.

나는 라틴어 ‘a’와는 구별되는 키릴 문자 ‘a’를 사용했습니다. 여기서 if 문에 사용 된 문자를 검사 할 수 있습니다 .

변수 이름이 다른 알파벳에서 가져 오기 때문에 작동합니다. 그것들은 별개의 식별자이며 각각 다른 값을 가진 두 개의 별개의 변수를 만듭니다.

이 코드가 제대로 작동하려면 문자 인코딩을 두 문자를 모두 지원하는 문자로 변경해야합니다 (예 : 모든 유니 코드 인코딩 (UTF-8, UTF-16 (BE 또는 LE)), UTF-32, 심지어 UTF-7) ) 또는 Windows-1251, ISO 8859-5, KOI8-R ( Thomas WellerPa Elo Ebermann- 감사합니다 ) :

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

(향후 언제라도 이런 종류의 문제를 다루지 않아도되기를 바랍니다.)


답변

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

}


답변

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

이데온에서


그러나 이것이 유니 코드로 할 수있는 최악의 일은 아닙니다. 유효한 식별자 부분 인 공백이나 제어 문자를 사용 하거나 같은 모양의 다른 문자를 사용 하면 텍스트 검색을 수행 할 때와 같이 다르게 식별 될 수있는 식별자가 생성됩니다.

하지만이 프로그램은

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

적어도 유니 코드 관점에서 볼 때 동일한 두 개의 식별자를 사용합니다. 그들은 and를 ä사용하여 동일한 문자를 인코딩하는 다른 방법을 사용합니다.U+00E4U+0061 U+0308 .

이데온에서

따라서 사용하는 도구에 따라 동일하게 보일뿐만 아니라 유니 코드 가능 텍스트 도구도 차이를보고하지 않을 수 있으며 검색시 항상 두 가지를 모두 찾을 수 있습니다. 소스 코드를 다른 사람에게 복사 할 때 다른 표현이 손실되는 문제가있을 수 있습니다. 아마도 “이상한 동작”에 대한 도움말을 얻으려고 시도하면 도우미가 재현 할 수 없게됩니다.


답변

@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 병렬 스트림 ForkJoinPool은 후드에서 사용되며 변수 a 는 동기화없이 여러 스레드간에 공유되므로 결과가 결정적이지 않습니다.