但是有可能在Java下面给出的条件下打印"成功"消息吗?
if (a==1 && a==2 && a==3) {
System.out.println("Success");
}
Run Code Online (Sandbox Code Playgroud)
有人建议:
int _a = 1;
int a = 2;
int a_ = 3;
if (_a == 1 && a == 2 && a_ == 3) {
System.out.println("Success");
}
Run Code Online (Sandbox Code Playgroud)
但通过这样做,我们正在改变实际变量.还有其他方法吗?
Erw*_*idt 320
是的,如果你将变量声明a为volatile ,那么使用多个线程很容易实现这一点.
一个线程不断地将变量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();
}
}
Run Code Online (Sandbox Code Playgroud)
phf*_*ack 84
使用来自精彩代码高尔夫答案的概念(和代码),Integer可以混淆值.
在这种情况下,当它们通常不是这样时,它可以使ints Integer成为平等:
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");
}
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,它并不像Erwin Bolwidt的多线程答案 那样优雅(因为这需要Integer演员),但仍然会发生一些有趣的恶作剧.
Pad*_*ado 49
在这个问题中, @ oooobe建议(并建议不要)在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");
}
}
Run Code Online (Sandbox Code Playgroud)
如果使用下面的命令执行时会输出恰好一个Success:
cpp -P src/Main.java Main.java && javac Main.java && java Main
Run Code Online (Sandbox Code Playgroud)
Prz*_*kal 38
正如我们已经知道的那样,由于Erwin Bolwidt和phflack的很好的答案,有可能使这个代码评估为真,我想表明在处理看起来像一个呈现的条件时你需要保持高水平的注意力在这个问题中,有时你所看到的可能并不完全是你认为的那样.
这是我尝试显示此代码打印Success!到控制台.我知道我有点作弊,但我仍然认为这是一个在这里展示它的好地方.
无论编写这样的代码的目的是什么 - 更好地知道如何处理以下情况以及如何检查您认为自己看到的内容是否错误.
我使用了西里尔语'a',这是拉丁语'a'中的一个独特角色.您可以在此处检查if语句中使用的字符.
这是有效的,因为变量的名称取自不同的字母表.它们是不同的标识符,创建两个不同的变量,每个变量具有不同的值.
请注意,如果您希望此代码正常工作,则需要将字符编码更改为支持两个字符的编码,例如所有Unicode编码(UTF-8,UTF-16(BE或LE),UTF-32,甚至UTF-7) ),或Windows-1251,ISO 8859-5,KOI8-R(谢谢你 - Thomas Weller和PaŭloEbermann - 指出来):
public class A {
public static void main(String[] args) {
int ? = 0;
int a = 1;
if(? == 0 && a == 1) {
System.out.println("Success!");
}
}
}
Run Code Online (Sandbox Code Playgroud)
(我希望将来任何时候都不会遇到这类问题.)
Erw*_*idt 26
使用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());
}
}
}
Run Code Online (Sandbox Code Playgroud)
Hol*_*ger 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");
}
}
}
Run Code Online (Sandbox Code Playgroud)
但请注意,这不是你用Unicode做的最糟糕的事情.使用作为有效标识符部分的白色空格或控制字符或使用看起来相同的不同字母仍会创建不同且可被发现的标识符,例如在进行文本搜索时.
但这个计划
public class Q48383521 {
public static void main(String[] args) {
int a? = 1;
int ä = 2;
if(a? == 1 && ä == 2) {
System.out.println("success");
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用两个相同的标识符,至少从Unicode的角度来看.他们只是使用不同的方法来编码相同的字符ä,使用U+00E4和U+0061 U+0308.
因此,根据您使用的工具,它们可能不仅看起来相同,启用Unicode的文本工具甚至可能不会报告任何差异,在搜索时始终找到两者.在将源代码复制到其他人时,您甚至可能会遇到不同表示形式丢失的问题,可能试图获取"奇怪行为"的帮助,使其对助手不可重现.
| 归档时间: |
|
| 查看次数: |
20608 次 |
| 最近记录: |