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
값이 엉망이 될 수있다.
이 경우 일반적으로 그렇지 않을 때 int
s로 캐스팅 된 Integer
s를 동일하게 만들 수 있습니다.
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");
}
}
Unfortunately it's not quite as elegant as Erwin Bolwidt's multithreaded answer (as this one requires Integer
casting), but still some fun shenanigans take place.
In this question @aioobe suggests (and advise against) the use of C preprocessor for Java classes.
Although it is extremely cheaty, that's my solution:
#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");
}
}
If executed using the following commands it will output exactly one Success
:
cpp -P src/Main.java Main.java && javac Main.java && java Main
As we already know that it is possible to make this code evaluate to true thanks to great answers of Erwin Bolwidt and phflack, I wanted to show that you need to keep a high level of attention when dealing with a condition that looks like the one presented in the question, as sometimes what you see might not be exactly what you think it is.
This is my attempt to show that this code prints Success!
to the console. I know I cheated a bit, but I still think this is a good place to present it right here.
No matter what the purposes of writing code like this are - better to know how to deal with the following situation and how to check if you're not wrong with what you think you see.
I used the Cyrillic 'a' which is a distinct character from the latin 'a'. You can inspect the characters used in the if statement here.
This works because the names of the variables are taken from different alphabets. They are distinct identifiers, creating two distinct variables with a different value in each.
Note that if you want this code to work properly, character encoding needs to be changed to one supporting both characters, e.g. all Unicode encodings (UTF-8, UTF-16 (in BE or LE), UTF-32, even UTF-7), or Windows-1251, ISO 8859-5, KOI8-R (thank you - Thomas Weller and Paŭlo Ebermann - for pointing it out):
public class A {
public static void main(String[] args) {
int а = 0;
int a = 1;
if(а == 0 && a == 1) {
System.out.println("Success!");
}
}
}
(I hope you will never have to deal with that sort of problem any time in the future.)
There is another way to approach this (in additional to the volatile data-racing approach that I posted earlier), using the power of PowerMock. PowerMock allows methods to be replaced with other implementations. When that is combined with auto-unboxing, the original expression (a == 1 && a == 2 && a == 3)
, without modification, can be made true.
@phflack's answer relies on modifying the auto-boxing process in Java that uses the Integer.valueOf(...)
call. The below approach relies on modifying auto-unboxing by changed the Integer.intValue()
call.
The advantage of the below approach is that the original if-statement given by the OP in the question is used unchanged, which I think is the most elegant.
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());
}
}
}
Since this seems to be a follow-up of this JavaScript question, it’s worth noting that this trick and similar works in Java too:
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");
}
}
}
But note that this isn’t the worst thing you could do with Unicode. Using white-space or control characters that are valid identifiers parts or using different letters that look the same still creates identifiers that are different and can be spotted, e.g. when doing a text search.
But this program
public class Q48383521 {
public static void main(String[] args) {
int ä = 1;
int ä = 2;
if(ä == 1 && ä == 2) {
System.out.println("success");
}
}
}
uses two identifiers that are the same, at least from the Unicode point of view. They just use different ways to encode the same character ä
, using U+00E4
and U+0061 U+0308
.
So depending on the tool you’re using, they may not only look the same, Unicode enabled text tools may not even report any difference, always finding both when searching. You may even have the problem that the different representations get lost when copying the source code to someone else, perhaps trying to get help for the “weird behavior”, making it non-reproducible for the helper.
Inspired by the @Erwin's excellent answer, I wrote a similar example, but using Java Stream API.
And an interesting thing is that my solution works, but in very rare cases (because just-in-time
compiler optimizes such a code).
The trick is to disable any JIT
optimizations using the following VM
option:
-Djava.compiler=NONE
In this situation, the number of success cases increases significantly. Here is the code:
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");
}
}
}
P.S. Parallel streams use ForkJoinPool
under the hood, and variable a is shared between multiple threads without any synchronization, that's why the result is non-deterministic.
Along similar lines, by forcing a float (or double) to underflow (or overflow) through division (or multiplication) by a large number:
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");
}
참고URL : https://stackoverflow.com/questions/48383521/can-a-1-a-2-a-3-evaluate-to-true-in-java
'development' 카테고리의 다른 글
스토리 보드-식별자가있는 뷰 컨트롤러를 포함하지 않습니다 (0) | 2020.05.26 |
---|---|
SQL RANK () 대 ROW_NUMBER () (0) | 2020.05.26 |
libc ++ abi.dylib : NSException (lldb) 유형의 포착되지 않은 예외로 종료 (1) | 2020.05.26 |
"느슨한 커플 링"이란 무엇입니까? (0) | 2020.05.26 |
IntelliJ에서 코드 글꼴 크기를 늘리는 방법은 무엇입니까? (0) | 2020.05.26 |