Вот код, который я нашел в интернете:
class M{public static void main(String[]a){System.out.print(new char[]
{'H','e','l','l','o',' ','W','o','r','l','d','!'});}}
Этот код печатается Hello World!
на экране; Вы можете видеть, что это бежит здесь . Я ясно вижу public static void main
написанное, но это задом наперед. Как работает этот код? Как это вообще компилируется?
Редактировать: я попробовал этот код в IntellIJ, и он отлично работает. Однако по какой-то причине он не работает в notepad ++ вместе с cmd. Я до сих пор не нашел решения этой проблемы, поэтому, если кто-нибудь найдет, прокомментируйте ниже.
java
unicode
right-to-left
Мнимая Тыква
источник
источник
M
а также после[]a
: fileformat.info/info/unicode/char/202d/index.htm. Он называется LEFT-TO-RIGHT OVERRIDEniam diov citats cilbup
звучит как латинская пословица ..Ответы:
Здесь есть невидимые символы, которые изменяют способ отображения кода. В Intellij их можно найти, скопировав код в пустую строку (
""
), которая заменяет их на экранированные Unicode, удаляя их эффекты и раскрывая порядок, который видит компилятор.Вот результат этой копии-вставки:
Символы исходного кода хранятся в этом порядке, и компилятор обрабатывает их как в этом порядке, но они отображаются по-разному.
Обратите внимание на
\u202E
символ, который является переопределением справа налево, начиная блок, где все символы должны отображаться справа налево, и\u202D
слева направо, начиная вложенный блок, где все символы приводятся в порядке слева направо, переопределяя первое переопределение.Ergo, когда он отображает исходный код,
class M
отображается нормально, но\u202E
меняет порядок отображения всего оттуда до\u202D
, что снова меняет все. (Формально все, начиная с конца и до конца\u202D
строки, меняется на противоположное дважды, один раз из-за\u202D
и один раз, а остальная часть текста перевернута из-за\u202E
, поэтому этот текст отображается в середине строки вместо конца.) Направленность следующей строки обрабатывается независимо от первой из-за ограничителя строки, поэтому{'H','e','l','l','o',' ','W','o','r','l','d','!'});}}
отображается нормально.Для полного (чрезвычайно сложного, двунаправленного алгоритма Unicode) см. Приложение № 9 к Стандартному Unicode .
источник
Это выглядит иначе из-за двунаправленного алгоритма Unicode . Существует два невидимых символа RLO и LRO, которые двунаправленный алгоритм Unicode использует для изменения визуального представления символов, вложенных между этими двумя метасимволами.
В результате они визуально выглядят в обратном порядке, но действительные символы в памяти не меняются местами. Вы можете проанализировать результаты здесь . Компилятор Java будет игнорировать RLO и LRO и обрабатывать их как пробелы, поэтому код компилируется.
Примечание 1: Этот алгоритм используется текстовыми редакторами и браузерами для визуального отображения символов как символов LTR (английский), так и символов RTL (например, арабский, иврит) одновременно - следовательно, «bi» -направленный. Вы можете прочитать больше о Двунаправленном алгоритме на сайте Unicode .
Примечание 2: Точное поведение LRO и RLO определено в разделе 2.2 Алгоритма.
источник
M\u202E
иa\u202D
, но эти идентификаторы, по-видимому, рассматриваются как эквивалентныеM
иa
. (JLS не очень хорошо объясняет это.)Персонаж
U+202E
отражает код справа налево, хотя он очень умный. Скрыт, начиная с М,Ну, сначала, когда я увидел жесткий вопрос, «это своего рода шутка, потерять кого-то еще раз», но затем я открыл свою IDE («IntelliJ»), создал класс и пропустил код ... и это скомпилировано !!! Итак, я посмотрел получше и увидел, что «общедоступная статическая пустота» была задом наперед, поэтому я пошел туда с курсором и удалил несколько символов ... И что происходит? Символы начали стираться задом наперед , поэтому я подумал, ммм ... редко ... я должен выполнить ее ... Итак, я продолжаю выполнять программу, но сначала мне нужно было сохранить ее ... и это было, когда я нашел это! , Я не смог сохранить файл, потому что моя IDE сказала, что для некоторого символа была другая кодировка, и укажи мне, где это былоИтак, я начинаю исследование в Google для специальных символов, которые могли бы сделать работу, и все :)
двунаправленный алгоритм Unicode, и
U+202E
вкратце, объясню :Зачем создавать такой алгоритм, как этот ?
источник
Глава 3 спецификации языка дает объяснение, подробно описывая, как осуществляется лексический перевод для Java-программы. Что важнее всего для вопроса:
Таким образом, программа написана в символах Unicode, и автор может избежать их использования,
\uxxxx
если кодировка файла не поддерживает символ Unicode, и в этом случае она переводится в соответствующий символ. Одним из символов Unicode, присутствующих в этом случае, является\u202E
. Он не отображается визуально во фрагменте, но если вы попытаетесь переключить кодировку браузера, могут появиться скрытые символы.Следовательно, лексический перевод приводит к объявлению класса:
что означает , что идентификатор класса
M\u202E
. Спецификация рассматривает это как действительные идентификтор:источник