Can (a == 1 && a == 2 && a == 3) evaluate true in Java?

We know that this is possible in JavaScript .

But is it possible to print the message “Success” under the condition below in Java?

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

Someone suggested:

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

But by doing this, we change the actual variable. Is there another way?

+160
source share
8 answers

Yes, it is quite easy to achieve this with multiple threads if you declare the variable a as mutable.

One thread constantly changes the variable a from 1 to 3, and the other thread constantly checks that a == 1 && a == 2 && a == 3 . This happens often enough for a continuous stream of Success to be printed to the console.

(Note that if you add the else {System.out.println("Failure");} clause, you will see that the test crashes much more often than it does.)

In practice, it also works without declaring a as volatile, but only 21 times on my MacBook. Without volatile compiler or HotSpot is allowed to cache a or replace the if with if (false) . Most likely, HotSpot starts after a while and compiles it into build instructions that cache the value of a . With volatile it retains the seal of "Success" forever.

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

Using the concepts (and code) from the brilliant answer to golf for golf , Integer values ​​can be messed up.

In this case, it can make int equal to Integer equal if they usually will not:

 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, this is not as elegant as the multi-threaded answer of Erwin Bolwidt (since Integer casting is required for this), but still there are some funny frauds.

+80
source

In this question, @aioobe suggests (and advises) using the C preprocessor for Java classes.

Even though cheaty is extremely what my solution is:

 #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 returns exactly one Success :

 cpp -P src/Main.java Main.java && javac Main.java && java Main 
+47
source

As we already know, it is possible that this code be evaluated as true thanks to the great answers of Erwin Bolwidt and phflack , I wanted to show that you need to pay special attention when working with a condition that looks like it is presented in the question, because sometimes, what you see may not be what you think.

This is my attempt to show that this code prints Success! on the console. I know I cheated a little , but I still think this is a good place to introduce it here.

Regardless of what the purpose of writing such code is, it is better to know how to cope with the following situation and how to check whether you are mistaken with what you think you see.

I used the Cyrillic alphabet 'a', which is a great Latin character 'a'. You can check the characters used in the if statement here .

This works because variable names come from different alphabets. They are different identifiers, creating two different variables with different values ​​in each.

Please note that if you want this code to work correctly, the character encoding should be replaced by one that supports both characters, for example. all Unicode encodings (UTF-8, UTF-16 (in BE or LE), UTF-32, even UTF-7) or Windows-1251, ISO 8859-5, KOI8-R (thanks - Thomas Weller and Paŭlo Ebermann - for instructions of it):

 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 never have to deal with such problems in the future).

+36
source

There is another way to approach this (in addition to the unsustainable approach using data that I published earlier) using the power of PowerMock. PowerMock allows you to replace methods with other implementations. When this is combined with automatic unpacking, the original expression (a == 1 && a == 2 && a == 3) can be executed without changes.

@phflack answer depends on the modification of the automatic boxing process in Java, which uses the Integer.valueOf(...) call. The approach below is based on changing automatic unpacking by changing the call to Integer.intValue() .

The advantage of the following approach is that the original if-statement asked by the OP in the question is used unchanged, which, in my opinion, 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()); } } } 
+24
source

Since this seems to be a continuation 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; int2 = 3; int a = 3; if(aᅠ==1 && a==ᅠ2 && a==3) { System.out.println("success"); } } } 

At Ideone


But note that this is not the worst thing you could do with Unicode. Using white or control characters that are valid identification parts or using different letters that look the same still creates identifiers that are different and can be noticed, for example. when performing 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 a Unicode perspective. They simply use different encoding methods for the same ä character, using U+00E4 and U+0061 U+0308 .

On ideone

Thus, depending on the tool you use, they may not only look the same, but Unicode-enabled text tools may not even report any differences, always finding them when searching. Perhaps you may have a problem with the fact that different views are lost when copying the source code to someone else, maybe trying to get help for "strange behavior", which makes it irreproducible for the assistant.

+16
source

Inspired by @Erwin's excellent answer , I decided to prove that this is possible using the Java Stream API (parallel streams to be exact). Technically, the approach is the same, just a different interpretation.

Interestingly, my solution works, but in very rare cases (the compiler can optimize the code on time).

The trick is to turn off any JIT optimizations using the following VM option:

 -Djava.compiler=NONE 

In this situation, the number of successful cases increases significantly! Here is my 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"); } } } 

A parallel thread uses ForkJoinPool under the hood, so the variable a is divided between several threads without any synchronization, so the result is not deterministic.

+3
source

Along similar lines , causing the float (or double) to overflow (or overflow) by dividing (or multiplying) 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"); } 
+1
source

Source: https://habr.com/ru/post/1274999/


All Articles