Мы знаем, что это возможно в 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");
}
Но, делая это, мы меняем фактическую переменную. Есть ли другой путь?
&&
является логическимand
оператором, что означает, что онa
должен иметь значения 1, 2 и 3 одновременно, что логически невозможно. Ответ НЕТ, не возможно. Вы хотите написатьif
утверждение, которое проверяет,a
имеет ли одно из значений 1, 2 ИЛИ 3?yes
_
, за исключением того, что вы его не видите.if(a==1 && a==2 && a==3)
не обязательно оценивается одновременно. И это можно использовать, чтобы сделать эту работу, не прибегая к уловкам Unicode.Ответы:
Да, это легко сделать с помощью нескольких потоков, если вы объявите переменную
a
как volatile.Один поток постоянно меняет переменную от 1 до 3, а другой поток постоянно проверяет это
a == 1 && a == 2 && a == 3
. Это происходит достаточно часто, чтобы на консоли печатался непрерывный поток «Success».(Обратите внимание, что если вы добавите
else {System.out.println("Failure");}
предложение, вы увидите, что тест проваливается гораздо чаще, чем успешно.)На практике это также работает, не объявляя
a
как изменчивый, но только 21 раз на моем MacBook. Безvolatile
этого компилятору или HotSpot разрешено кэшироватьa
или заменятьif
операторif (false)
. Скорее всего, HotSpot запускается через некоторое время и компилирует его в инструкции по сборке, которые кешируют значениеa
. Сvolatile
, он продолжает печатать «Успех» навсегда.источник
volatile
, но в принципе это может произойти даже безvolatile
ключевого слова, и это может произойти произвольное количество раз, в то время как, с другой стороны, нет никаких гарантий, что это когда-либо произойдет, даже сvolatile
. Но, конечно, то, что это происходит на практике, впечатляет…volatile
. Барьеры памяти, созданные для реализации,volatile
замедляют потоки и повышают вероятность их синхронной работы в течение коротких периодов времени. Это происходит гораздо чаще, чем я ожидал. Это очень чувствительно ко времени, но я вижу примерно 0,2–0,8% оценок(a == 1 && a == 2 && a == 3)
доходностиtrue
.Используя понятия (и код) из блестящего гольфа-кода ,
Integer
можно смешивать значения.В этом случае он может сделать
int
s приведенным кInteger
s равным, когда они обычно не будут:К сожалению, он не так элегантен, как многопоточный ответ Эрвина Болвидта (так как этот требует
Integer
кастинга) , но все же происходят некоторые забавные махинации.источник
Integer
. Обидно в кастинге, но все равно круто.a
установка на 1/2/3 удовлетворитa == 1
, но не пойдет другим путемJava
. Наименее уродливая версия, которую я мог найти, - это использоватьa.equals(1) && a.equals(2) && a.equals(3)
, что заставляет1
,2
и3
быть автоматически загруженным какInteger
s.a
урок сboolean equals(int i){return true;}
?Integer a = 1;
этой строкой до сих пор ясно, что наa
самом деле это целое число.В этом вопросе @aioobe предлагает (и не советует) использовать препроцессор Си для классов Java.
Хотя это очень обманчиво, это мое решение:
Если он выполняется с использованием следующих команд, он выведет ровно одну
Success
:источник
a
что это переменная, но это может быть любой произвольный фрагмент кода в языках с препроцессором.Так как мы уже знаем, что этот код можно сделать истинным благодаря отличным ответам Эрвина Болвидта и phflack , я хотел показать, что вам нужно сохранять высокий уровень внимания при работе с условием, похожим на приведенное в вопросе, так как иногда то, что вы видите, может быть не совсем тем, что вы думаете.
Это моя попытка показать, что этот код печатается
Success!
на консоли. Я знаю, что немного обманул , но я все еще думаю, что это хорошее место, чтобы представить это прямо здесь.Неважно, каковы цели написания подобного кода - лучше знать, как справиться со следующей ситуацией и как проверить, не ошибаетесь ли вы с тем, что, по вашему мнению, вы видите.
Я использовал кириллицу «а», которая отличается от латинского «а». Вы можете просмотреть символы, используемые в операторе if здесь .
Это работает, потому что имена переменных взяты из разных алфавитов. Это разные идентификаторы, создающие две разные переменные с разными значениями в каждой.
Обратите внимание, что если вы хотите, чтобы этот код работал должным образом, кодировку символов необходимо изменить на кодировку, поддерживающую оба символа, например все кодировки Unicode (UTF-8, UTF-16 (в BE или LE), UTF-32, даже UTF-7). ) или Windows-1251, ISO 8859-5, KOI8-R (спасибо - Томас Веллер и Паŭло Эберманн - за указание на это):
(Надеюсь, вам никогда не придется сталкиваться с подобными проблемами в будущем.)
источник
а
и другоеa
работает, если вы сообщаете редактору, в какой кодировке он находится (и, возможно, компилятор тоже). Все кодировки Unicode работают (UTF-8, UTF-16 (в BE или LE), UTF-32, даже UTF-7), а также, например, Windows-1251, ISO 8859-5, KOI8-R.Есть другой способ приблизиться к этому (в дополнение к нестабильному подходу к гонке данных, который я опубликовал ранее), используя мощь PowerMock. PowerMock позволяет заменять методы другими реализациями. Когда это сочетается с автоматическим распаковыванием, исходное выражение
(a == 1 && a == 2 && a == 3)
без изменений может быть выполнено.Ответ @ phflack основан на изменении процесса автобокса в Java, который использует
Integer.valueOf(...)
вызов. Приведенный ниже подход основан на изменении автоматической распаковки путем измененияInteger.intValue()
вызова.Преимущество подхода, приведенного ниже, состоит в том, что исходное выражение if, данное OP в этом вопросе, используется без изменений, что я считаю наиболее элегантным.
источник
access$nnn
методы, используемые для чтенияprivate
полей внутренних / внешних классов? Это позволило бы некоторые другие интересные варианты (которые даже работают сint
переменной) ...(Integer)2
) упаковывает int. Если взглянуть больше на рефлексию , то похоже, что это невозможно сделать с распаковкой с использованием рефлексии, но вместо этого это возможно с помощью Instrumentation (или с PowerMock, как в этом ответе)access$0
и существование метода проверяется при регистрации. Но замена никогда не вызывается.Поскольку этот вопрос, похоже, является продолжением этого вопроса JavaScript , стоит отметить, что этот прием и аналогичные действия работают и в Java:
По идоне
Но учтите, что это не самое худшее, что вы можете сделать с Unicode. Использование пробелов или управляющих символов, которые являются допустимыми частями идентификаторов, или использование разных букв, которые выглядят одинаково, по- прежнему создают идентификаторы, которые различаются и могут быть обнаружены, например, при выполнении текстового поиска.
Но эта программа
использует два одинаковых идентификатора, по крайней мере, с точки зрения Unicode. Они просто используют разные способы кодирования одного и того же символа
ä
, используяU+00E4
иU+0061 U+0308
.По идоне
Поэтому, в зависимости от используемого вами инструмента, они могут не только выглядеть одинаково, текстовые инструменты с поддержкой Unicode могут даже не сообщать о каких-либо различиях, всегда находя и то и другое при поиске. У вас может даже быть проблема, что различные представления теряются при копировании исходного кода кому-то еще, возможно, пытаясь получить помощь для «странного поведения», что делает его невоспроизводимым для помощника.
источник
int ᅠ2 = 3;
это намеренно? Потому что я вижу очень странный кодa
), в то время как речь идет о пробеле, и, в общем , это заслуга даже более старых ответов на связанный вопрос JavaScript. Обратите внимание, что мой комментарий там даже старше, чем вопрос Java (на несколько дней)…Вдохновленный отличным ответом @ Erwin , я написал похожий пример, но с использованием Java Stream API .
И что интересно, мое решение работает, но в очень редких случаях (потому что
just-in-time
компилятор оптимизирует такой код).Хитрость заключается в том, чтобы отключить любые
JIT
оптимизации, используя следующуюVM
опцию:В этой ситуации количество случаев успеха значительно увеличивается. Вот код:
PS Параллельные потоки используются
ForkJoinPool
под капотом, а переменная a совместно используется несколькими потоками без какой-либо синхронизации, поэтому результат является недетерминированным.источник
В том же ключе , заставляя float (или double) потерять (или переполнить) с помощью деления (или умножения) на большое число:
источник