在Java中(a==1&;a==2&;a==3)是否可以计算为true?

在Java中(a==1&;a==2&;a==3)是否可以计算为true?,java,Java,但是,在Java中,是否可以在下面给出的条件下打印“Success”消息 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"); }

但是,在Java中,是否可以在下面给出的条件下打印“Success”消息

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
声明为volatile,那么使用多个线程很容易实现这一点

一个线程不断地将变量a从1更改为3,另一个线程不断地测试
a==1&&a==2&&a==3
。这种情况经常发生,控制台上打印出连续的“成功”信息流

(注意,如果您添加一个
else{System.out.println(“Failure”);}
子句,您将看到测试失败的次数远远多于成功的次数。)

实际上,它也可以在不将
a
声明为volatile的情况下工作,但在我的MacBook上只有21次。如果没有
volatile
,编译器或热点可以缓存
a
,或将
if
语句替换为
if(false)
。最有可能的情况是,HotSpot会在一段时间后启动并将其编译为汇编指令,这些指令会缓存
a
的值。使用
volatile
,它将永远打印“成功”

公共类volatierace{
私人住宅;
公开作废开始(){
新线程(this::test).start();
新线程(this::change).start();
}
公开无效测试(){
while(true){
如果(a==1&&a==2&&a==3){
System.out.println(“成功”);
}
}
}
公共空间更改(){
while(true){
对于(int i=1;i<4;i++){
a=i;
}
}
}
公共静态void main(字符串[]args){
新volatierace().start();
}
}

正如我们已经知道的,由于埃尔文·博维特和phflack的出色回答,使该代码评估为真是可能的,我想表明,在处理问题中所述的情况时,你需要保持高度的注意力,因为有时候你看到的可能和你想象的不完全一样

这是我试图显示此代码打印
成功到控制台我知道我有点作弊,但我仍然认为这是一个展示这一点的好地方

无论编写这样的代码的目的是什么,最好知道如何处理以下情况,以及如何检查您所看到的内容是否正确

我使用西里尔字母“a”,这是一个与拉丁字母“a”不同的字符。您可以检查if语句中使用的字符

这是因为变量的名称取自不同的字母表。它们是不同的标识符,创建两个不同的变量,每个变量的值不同

请注意,如果希望此代码正常工作,则需要将字符编码更改为支持两个字符的编码,例如所有Unicode编码(UTF-8、UTF-16(在be或LE中)、UTF-32、甚至UTF-7)或Windows-1251、ISO 8859-5、KOI8-R(感谢托马斯·韦勒和帕罗·埃伯曼指出这一点):

(我希望你以后任何时候都不必处理这类问题。)

使用整数中的概念(和代码)
值可能会出错

在这种情况下,它可以使铸造为
Integer
s的
int
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");
    }
}

不幸的是,它不像(因为这一次需要
Integer
casting)那样优雅,但仍然会有一些有趣的恶作剧发生。

因为这似乎是对的后续,值得注意的是,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可以做的最糟糕的事情。使用作为有效标识符部分的空白或控制字符,或仍然创建不同且可以被发现的标识符,例如在执行文本搜索时

但是这个节目

公共类Q48383521{
公共静态void main(字符串[]args){
int ả=1;
intä=2;
如果(ả==1&&a==2){
System.out.println(“成功”);
}
}
}
至少从Unicode的角度来看,使用两个相同的标识符。他们只是使用不同的方式来编码相同的字符
a
,使用
U+00E4
U+0061u+0308

因此,根据您使用的工具的不同,它们可能不仅看起来相同,启用Unicode的文本工具甚至可能不会报告任何差异,在搜索时总是同时查找这两种工具。您甚至可能会遇到这样的问题,即在将源代码复制给其他人时,不同的表示形式会丢失,可能是试图为“奇怪的行为”获取帮助,使其对帮助程序不可复制。

在@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");
    }
}
如果使用以下命令执行,它将只输出一个
Success

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

还有另一种方法可以实现这一点(除了我之前发布的volatile data racing方法之外),使用PowerMock的强大功能。PowerMock允许用其他实现替换方法。当这与自动取消装箱相结合时,原始表达式
(a==1&&a==2&&a==3)
,无需修改即可变为真

@phflack的答案依赖于修改Java中使用
Integer.valueOf(…)
调用的自动装箱过程。下面的方法依赖于通过更改
Integer.intValue()
调用来修改自动取消装箱

以下方法的优点是,OP在问题中给出的原始if语句未被更改,我
#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");
    }
}
cpp -P src/Main.java Main.java && javac Main.java && java Main
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());
        }
    }

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