Как переменная Java может отличаться от самой себя?
Мне интересно, можно ли решить этот вопрос на Java (я новичок в языке). Это код:
class Condition {
// you can change in the main
public static void main(String[] args) {
int x = 0;
if (x == x) {
System.out.println("Ok");
} else {
System.out.println("Not ok");
}
}
}
В моей лаборатории я получил следующий вопрос: как вы можете пропустить первый случай (т.е. сделать условие x == x
ложным) без изменения самого условия?
Ответы
Ответ 1
Один простой способ - использовать Float.NaN
:
float x = Float.NaN; // <--
if (x == x) {
System.out.println("Ok");
} else {
System.out.println("Not ok");
}
Not ok
Вы можете сделать то же самое с Double.NaN
.
Из JLS §15.21.1. Операторы числового равенства ==
и !=
:
Тестирование равенства с плавающей точкой выполняется в соответствии с правилами стандарта IEEE 754:
-
Если либо операнд NaN, то результат ==
равен false
, но результат !=
равен true
.
Действительно, тест x!=x
равен true
тогда и только тогда, когда значение x
равно NaN.
...
Ответ 2
int x = 0;
if (x == x) {
System.out.println("Not ok");
} else {
System.out.println("Ok");
}
Ответ 3
В Спецификации языка Java NaN
не равно NaN
.
Поэтому любая строка, которая вызвала бы x
равным NaN
, вызовет это, например
double x=Math.sqrt(-1);
Из спецификации языка Java:
Операторы с плавающей запятой не производят исключений (§11). Операция что переполнение создает подписанную бесконечность, операцию, которая underflows производит денормализованное значение или подписанный ноль, а операция, которая не имеет математически определенного результата, дает NaN. Все в результате числовые операции с NaN в качестве операнда производят NaN. В виде уже описано, NaN неупорядочен, поэтому числовое сравнение операция с участием одного или двух NaN возвращает false и любой != сравнение с использованием NaN возвращает true, включая x!= x, когда x является NaN.
Ответ 4
Не уверен, что это опция, но изменение x
из локальной переменной в поле позволит другому потоку изменить его значение между чтением влево и вправо в инструкции if
.
Вот короткая демонстрация:
class Test {
static int x = 0;
public static void main(String[] args) throws Exception {
Thread t = new Thread(new Change());
t.setDaemon(true);
t.start();
while (true) {
if (x == x) {
System.out.println("Ok");
} else {
System.out.println("Not ok");
break;
}
}
}
}
class Change implements Runnable {
public void run() {
while (true)
Test.x++;
}
}
Вывод:
⋮
Ok
Ok
Ok
Ok
Ok
Ok
Ok
Ok
Not ok
Ответ 5
Замененная строка может быть прочитана.
double x = Double.NaN;
Это приведет к печати печатаемой страницы.
Спецификация языка Java (JLS) говорит:
Операторы с плавающей запятой не производят исключений (§11). Операция, которая переполняет, создает подписанную бесконечность, операция, которая выполняется под потоком, создает денормализованное значение или подписанный нуль, а операция, не имеющая математически определенного результата, дает NaN. В результате числовые операции с NaN в качестве операнда дают NaN. Как уже было описано, NaN неупорядочен, поэтому операция числового сравнения с одним или двумя NaN возвращает false, а любое!= Сравнение с NaN возвращает true, включая x!= X, когда x является NaN.
Ответ 6
Мне удалось получить Gotcha!
из этого:
volatile Object a = new Object();
class Flipper implements Runnable {
Object b = new Object();
public void run() {
while (true) {
Object olda = a;
a = b;
a = olda;
}
}
}
public void test() {
new Thread(new Flipper()).start();
boolean gotcha = false;
while (!gotcha) {
// I've added everything above this - I would therefore say still legal.
if (a == a) {
System.out.println("Not yet...");
} else {
System.out.println("Gotcha!");
// Uncomment this line when testing or you'll never terminate.
//gotcha = true;
}
}
}
Ответ 7
Существует так много решений:
class A extends PrintStream {
public A(PrintStream x) {super(x);}
public void println(String x) {super.println("Not ok");}
public static void main(String[] args) {
System.setOut(new A(System.out));
int x = 0;
if (x == x) {
System.out.println("Ok");
} else {
System.out.println("Not ok");
}
}
}
Ответ 8
Одно из простых решений:
System.out.println("Gotcha!");if(false)
if( a == a ){
System.out.println("Not yet...");
} else {
System.out.println("Gotcha!");
}
Но я не знаю всех правил этой загадки...
:)
Я знаю, что это обман, но, не зная всех правил, это самое легкое решение вопроса:)
Ответ 9
Создайте свой собственный класс System
в том же пакете с Condition
.
В этом случае ваш класс System
скроет java.lang.System
class
class Condition
{
static class System
{
static class out
{
static void println(String ignored)
{
java.lang.System.out.println("Not ok");
}
}
}
public static void main (String[] args) throws java.lang.Exception
{
int x = 0;
if (x == x)
{
System.out.println("Not ok");
}
else
{
System.out.println("Ok");
}
}
}
Идеальный DEMO
Ответ 10
Используя один и тот же подход пропуска/изменения вывода из другого ответа:
class Condition {
public static void main(String[] args) {
try {
int x = 1 / 0;
if (x == x) {
System.out.println("Ok");
} else {
System.out.println("Not ok");
}
} catch (Exception e) {
System.out.println("Not ok");
}
}
}