Глава 3. Лексическая структура
Содержание
В этой главе описывается лексическая структура языка программирования Java.
Программы написаны на Юникоде (§3.1), но обеспечиваются лексические преобразования (§3.2), чтобы можно было использовать экранирование Юникода (§3.3) для включения любых символов Юникода с помощью только символов ASCII. Определены разделители строк (§3.4), чтобы поддерживать различные соглашения существующих систем, сохраняя при этом согласованные номера строк.
Символы Юникода, полученные в результате лексических преобразований, сводятся к последовательности элементов ввода (§3.5), которые являются пробелами (§3.6), комментариями (§3.7) и токенами. Токены — это идентификаторы (§3.8), ключевые слова (§3.9), литералы (§3.10), разделители (§3.11) и операторы (§3.12) синтаксической грамматики.
Программы написаны с использованием набора символов Юникод (§1.7). Информацию об этом наборе символов и связанных с ним кодировках можно найти на сайте https://www.unicode.org/.
Java SE Platform отслеживает стандарт Юникод по мере его развития. Точная версия Юникода, используемая данным выпуском, указана в документации класса Character.
Версии языка программирования Java до JDK 1.1 использовали Юникод 1.1.5. Обновления до более новых версий стандарта Юникод происходили в JDK 1.1 (до Юникода 2.0), JDK 1.1.7 (до Юникода 2.1), Java SE 1.4 (до Юникода 3.0), Java SE 5.0 (до Юникода 4.0), Java SE 7 (до Юникода 6.0), Java SE 8 (до Юникода 6.2), Java SE 9 (до Юникода 8.0), Java SE 11 (до Юникода 10.0), Java SE 12 (до Юникода 11.0), Java SE 13 (до Юникода 12.1) и Java SE 15 (до Юникода 13.0).
Стандарт Юникод изначально был разработан как кодировка символов с фиксированной шириной 16 бит. С тех пор он был изменен, чтобы позволить символы, представление которых требует более 16 бит. Диапазон допустимых кодовых точек теперь U+0000 до U+10FFFF, используя шестнадцатеричную запись U+n. Символы, кодовые точки которых больше U+FFFF, называются дополнительными символами. Для представления всего диапазона символов с помощью только 16-битных единиц стандарт Юникод определяет кодировку UTF-16. В этой кодировке дополнительные символы представлены парами 16-битных кодовых единиц, первая из которых принадлежит диапазону верхних суррогатов (U+D800 до U+DBFF), а вторая — диапазону нижних суррогатов (U+DC00 до U+DFFF). Для символов в диапазоне U+0000 до U+FFFF значения кодовых точек и кодовых единиц UTF-16 совпадают.
Язык программирования Java представляет текст в последовательностях 16-битных кодовых единиц, используя кодировку UTF-16.
Некоторые API Java SE Platform, в основном в классе Character, используют 32-битные целые числа для представления кодовых точек как отдельных сущностей. Java SE Platform предоставляет методы для преобразования между 16-битными и 32-битными представлениями.
В этом документе используются термины кодовая точка и кодовая единица UTF-16, где представление актуально, и общий термин символ, где представление не имеет значения для обсуждения.
За исключением комментариев (§3.7), идентификаторов (§3.8) и содержимого символьных литералов, строковых литералов и текстовых блоков (§3.10.4, §3.10.5, §3.10.6), все элементы ввода (§3.5) в программе формируются только из символов ASCII (или экранирований Юникода (§3.3), которые приводят к символам ASCII).
ASCII (ANSI X3.4) — это американский стандартный код для обмена информацией. Первые 128 символов кодировки Unicode UTF-16 — это символы ASCII.
Поток исходных символов Юникода преобразуется в последовательность токенов с использованием следующих трех лексических шагов, которые применяются поочерёдно:
-
Преобразование экранирований Юникода (§3.3) в исходном потоке символов Юникода в соответствующий символ Юникода. Экранирование Юникода вида
\uxxxx, гдеxxxx— шестнадцатеричное значение, представляет кодовую единицу UTF-16, кодирование которой —xxxx. Этот шаг преобразования позволяет представить любую программу, используя только символы ASCII. -
Преобразование потока Юникода, полученного на шаге 1, в поток символов ввода и разделителей строк (§3.4).
-
Преобразование потока символов ввода и разделителей строк, полученного на шаге 2, в последовательность элементов ввода (§3.5), которые после удаления пробелов (§3.6) и комментариев (§3.7) составляют токены, которые являются терминальными символами синтаксической грамматики (§2.3).
На каждом шаге используется самое длинное возможное преобразование, даже если результат в итоге не формирует корректную программу, в то время как другое лексическое преобразование было бы таковым. Существует два исключения, чтобы учесть ситуации, требующие более тонкого преобразования: на шаге 1, для обработки последовательных \ символов (§3.3), и на шаге 3, для обработки контекстных ключевых слов и смежных > символов (§3.5).
Символы ввода a--b распознаются как a, -- и b, что не является частью какой-либо грамматически корректной программы, даже если распознавание a, -, -, b могло бы быть частью грамматически корректной программы. Распознавание a, -, -, b может быть реализовано с помощью символов ввода a- -b (с символом ASCII SP между двумя - символами).
Можно предположить, что исходный ввод \\u1234 преобразуется в символ \ и (в соответствии с правилом «самое длинное возможное») в экранирование Юникода вида \u1234. На самом деле, ведущий символ \ заставляет этот исходный ввод преобразовываться в семь различных символов: \ \ u 1 2 3 4.
Компилятор языка программирования Java ("компилятор Java") сначала распознаёт экранирования Юникода в своём исходном коде, преобразуя ASCII-символы \u, за которыми следуют четыре шестнадцатеричных цифры, в символ исходного кода, обозначающий единицу кодировки UTF-16 (§3.1) для указанного шестнадцатеричного значения. Одно экранирование Юникода может представлять символы в диапазоне U+0000 до U+FFFF; для представления дополнительных символов в диапазоне U+010000 до U+10FFFF требуется два последовательных экранирования Юникода. Все другие символы в исходном коде компилятора распознаются как символы исходного кода и передаются без изменений.
Этот этап преобразования приводит к последовательности символов ввода Юникода, все из которых являются символами исходного кода (любые экранирования Юникода были преобразованы в символы исходного кода).
u {u} 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F \, u и шестнадцатеричные цифры здесь — все ASCII-символы.
Производство СимволВводаЮникода неоднозначно, потому что ASCII-символ \ в исходном коде компилятора может быть преобразован либо в СимволИсходногоКода, либо в \ ЭкранированияЮникода (за которым следует ASCII-символ u). Чтобы избежать неоднозначности, при обработке каждого ASCII-символа \ в исходном коде компилятора необходимо учитывать последние символы исходного кода, полученные на данном этапе преобразования:
-
Если последний символ исходного кода в результате был сам преобразован из экранирования Юникода в исходном коде компилятора, то ASCII-символ
\может начинать экранирование Юникода.Например, если последний символ исходного кода в результате был обратной косой чертой, возникшей из экранирования Юникода
\u005cв исходном коде, то следующий ASCII-символ\в исходном коде может начинать ещё одно экранирование Юникода. -
В противном случае, посчитайте, сколько обратных косых черт подряд появились как символы исходного кода в результате, начиная от символа, отличного от обратной косой черты или от начала результата. (Не имеет значения, возникла ли такая обратная косая черта из ASCII-символа
\в исходном коде компилятора или из экранирования Юникода\u005cв исходном коде компилятора). Если это число чётное, то ASCII-символ\может начинать экранирование Юникода; если нечётное, то ASCII-символ\не может начинать экранирование Юникода.Например, исходный код
"\\u2122=\u2122"приводит к одиннадцати символам" \ \ u 2 1 2 2 = ™ ", так как, хотя второй ASCII-символ\в исходном коде не может начинать экранирование Юникода, третий ASCII-символ\может, а\u2122является кодировкой Юникода для символа™.
Если допустимый \ не следует за u, то он обрабатывается как СимволИсходногоКода и остаётся частью потока экранированного Юникода.
Если допустимый \ следует за u, или если за ним следует более одной u, и последняя u не следует за четырьмя шестнадцатеричными цифрами, то возникает ошибка времени компиляции.
Символ, полученный с помощью экранирования Юникода, не участвует в дальнейших экранированиях Юникода.
Например, исходный код \u005cu005a приводит к шести символам \ u 0 0 5 a, потому что 005c — это значение Юникода для обратной косой черты. Он не приводит к символу Z, который имеет значение Юникода 005a, потому что обратная косая черта, полученная в результате обработки экранирования Юникода \u005c, не интерпретируется как начало дальнейшего экранирования Юникода.
Обратите внимание, что \u005cu005a не может быть записан в строковой литерале для обозначения шести символов \ u 0 0 5 a. Это связано с тем, что первые два символа, полученные в результате преобразования, \ и u, интерпретируются в строковой литерале как недопустимая последовательность экранирования (§3.10.7).
К счастью, правило о последовательных символах обратной косой черты помогает программистам создавать исходные коды, обозначающие экранирования Юникода в строковой литерале. Для обозначения шести символов \ u
0 0 5 a в строковой литерале просто необходимо добавить ещё \ рядом с существующим \, например, "\\u005a is Z". Это работает, потому что вторая \ в исходном коде \\u005a не может начинать экранирование Юникода, поэтому первая \ и вторая \ сохраняются как символы исходного кода, как и следующие пять символов u 0 0 5 a. Две \ интерпретируются в строковой литерале как последовательность экранирования для обратной косой черты, что приводит к строке с желаемыми шестью символами \ u 0 0 5 a. Без правила исходный код \\u005a обрабатывался бы как символ исходного кода \, за которым следует экранирование Юникода \u005a, которое становится символом исходного кода Z; это было бы бесполезно, потому что \Z является недопустимой последовательностью экранирования в строковой литерале. (Обратите внимание, что правило преобразует \u005c\u005c в \\, потому что преобразование первого экранирования Юникода в символ исходного кода \ не препятствует преобразованию второго экранирования Юникода в другой символ исходного кода \.)
Это правило также позволяет программистам создавать исходные коды, обозначающие последовательности экранирования в строковой литерале. Например, исходный код \\\u006e приводит к трём символам \ \ n, потому что первая \ и вторая \ сохраняются как символы исходного кода, а третья \ может начинать экранирование Юникода, и поэтому \u006e преобразуется в символ исходного кода n. Три символа \ \ n интерпретируются в строковой литерале как \
n, что обозначает последовательность экранирования для перевода строки. (Обратите внимание, что \\\u006e может быть записано как \u005c\u005c\u006e, потому что каждое экранирование Юникода \u005c преобразуется в символ исходного кода \, поэтому оставшийся исходный код \u006e предшествует чётному числу обратных косых черт и обрабатывается как экранирование Юникода для n.)
Язык программирования Java определяет стандартный способ преобразования программы, написанной на языке Юникод, в ASCII, который преобразует программу в форму, которую могут обработать инструменты, основанные на ASCII. Преобразование включает в себя преобразование всех экранирований Юникода в исходном тексте программы в ASCII путём добавления дополнительной u — например, \uxxxx становится \uuxxxx — и одновременного преобразования символов в исходном тексте, не являющихся ASCII, в экранирования Юникода, содержащие по одному u.
Эта преобразованная версия так же приемлема для компилятора Java и представляет точно такую же программу. Точный исходный текст Юникода может быть восстановлен из этой ASCII-формы путём преобразования каждой последовательности экранирования, где присутствует несколько u, в последовательность символов Юникода с одной u меньше, и одновременного преобразования каждой последовательности экранирования с одной u в соответствующий единственный символ Юникода.
Компилятор Java должен использовать обозначение \uxxxx в качестве формата вывода для отображения символов Юникода, когда подходящий шрифт недоступен.
Компилятор Java затем разделяет последовательность символов ввода Юникод на строки, распознавая разделители строк.
символ ASCII CR, также известный как "возврат"
символ ASCII CR, за которым следует символ ASCII LF
Строки завершаются символами ASCII CR, или LF, или CR LF. Два символа CR, непосредственно за которыми следует LF, считаются одним разделителем строк, а не двумя.
Разделитель строк указывает на завершение формы комментария // (§3.7).
Строки, определяемые разделителями строк, могут определять номера строк, создаваемые компилятором Java.
Результат — последовательность разделителей строк и символов ввода, которые являются терминальными символами для третьего шага процесса токенизации.
Символы ввода и разделители строк, которые получаются после обработки символов Юникод (§3.3) и затем распознавания строк (§3.4), сводятся к последовательности элементов ввода.
Те элементы ввода, которые не являются пробелами или комментариями, являются токенами. Токены — терминальные символы синтаксической грамматики (§2.3).
Пробелы (§3.6) и комментарии (§3.7) могут служить для разделения токенов, которые, если будут рядом, могли бы быть токенизированы другим способом.
Например, символы ввода - и = могут образовывать операторный токен -= (§3.12) только в том случае, если между ними нет пробелов или комментариев. В качестве другого примера, десять символов ввода staticvoid образуют один токен идентификатора, в то время как одиннадцать символов ввода static void (с символом ASCII SP между c и v) образуют пару токенов ключевых слов, static и void, разделенных пробелами.
В качестве особой уступки для совместимости с некоторыми операционными системами символ ASCII SUB (\u001a, или управляющий символ Z) игнорируется, если он является последним символом в потоке экранированного ввода.
Производство Вход является неоднозначным, что означает, что для некоторых последовательностей символов ввода существует более одного способа уменьшения символов ввода до элементов ввода (то есть, токенизировать символы ввода). Неопределенности разрешаются следующим образом:
-
Последовательность символов ввода, которые могут быть сведены либо к токену идентификатора, либо к токену литерала, всегда сводится к токену литерала.
-
Последовательность символов ввода, которые могут быть сведены либо к токену идентификатора, либо к токену зарезервированного ключевого слова (§3.9), всегда сводится к токену зарезервированного ключевого слова.
-
Последовательность символов ввода, которые могут быть сведены либо к контекстному ключевому слову, либо к другим (не ключевым) токенам, уменьшается в соответствии с контекстом, как указано в §3.9.
-
Если символ ввода
>появляется в контексте типа (§4.11), то есть как часть Типа или UnannType в синтаксической грамматике (§4.1, §8.3), то он всегда сводится к оператору численного сравнения>, даже когда он может быть объединён с соседним символом>для образования другого оператора.Без этого правила для символов
>, два последовательных>скобки в типе, таком какList<List<String>>, были бы токенизированы как оператор сдвига вправо со знаком>>, в то время как три последовательных>скобки в типе, таком какList<List<List<String>>>, были бы токенизированы как оператор сдвига вправо без знака>>>. Хуже того, токенизация четырёх или более последовательных>скобок в типе, таком какList<List<List<List<String>>>>, была бы неоднозначной, так как различные комбинации токенов>,>>и>>>могли бы представлять символы>>>>.
Рассмотрим два токена x и y в результирующем потоке ввода. Если x предшествует y, то мы говорим, что x находится слева от y и что y находится справа от x.
Например, в этом простом фрагменте кода:
class Empty {
}
мы говорим, что токен } находится справа от токена {, даже если он появляется в этом двумерном представлении вниз и влево от токена {. Эта конвенция относительно использования слов слева и справа позволяет нам говорить, например, об правом операнде бинарного оператора или о левой части присваивания.
Пробелы определяются как символ ASCII пробела, символ горизонтальной табуляции, символ подачи страницы и символы разделителей строк (§3.4).
символ ASCII HT, также известный как "горизонтальная табуляция"
символ ASCII FF, также известный как "подача страницы"
РазделительСтроки
Существуют два вида комментариев:
-
/*текст*/Традиционный комментарий: весь текст от ASCII-символов
/*до ASCII-символов*/игнорируется (как в C и C++). -
//текстКомментарий в конце строки: весь текст от ASCII-символов
//до конца строки игнорируется (как в C++).
Эти правила подразумевают все следующие свойства:
-
Комментарии не вложены.
-
/*и*/не имеют специального значения в комментариях, начинающихся с//. -
//не имеет специального значения в комментариях, начинающихся с/*или/**.
В результате, следующий текст является одним полным комментарием:
/* this comment /* // /** ends here: */
Лексическая грамматика подразумевает, что комментарии не встречаются внутри символьных литералов, строковых литералов или текстовых блоков (§3.10.4, §3.10.5, §3.10.6).
Идентификатор — это последовательность неограниченной длины символов Java и цифр Java, первый из которых должен быть символом Java.
"Символ Java" — это символ, для которого метод Character.isJavaIdentifierStart(int) возвращает true.
"Символ Java или цифра" — это символ, для которого метод Character.isJavaIdentifierPart(int) возвращает true.
"Символы Java" включают заглавные и строчные латинские буквы ASCII A-Z (\u0041-\u005a), а также a-z (\u0061-\u007a), и, по историческим причинам, символ доллара ASCII ($, или \u0024) и знак подчеркивания (_, или \u005f). Символ доллара следует использовать только в автоматически генерируемом исходном коде или, в редких случаях, для доступа к имеющимся именам в legacy-системах. Знак подчеркивания может использоваться в идентификаторах, состоящих из двух или более символов, но не может использоваться в качестве идентификатора из одного символа, так как является ключевым словом.
"Цифры Java" включают цифры ASCII 0-9 (\u0030-\u0039).
Символы и цифры могут быть взяты из всего набора символов Unicode, который поддерживает большинство письменных систем, используемых в мире сегодня, включая большие наборы для китайского, японского и корейского языков. Это позволяет программистам использовать идентификаторы в своих программах, написанных на родном языке.
Два идентификатора совпадают только тогда, когда, после игнорирования игнорируемых символов, идентификаторы имеют одинаковый символ Unicode для каждой буквы или цифры. Игнорируемый символ — это символ, для которого метод Character.isIdentifierIgnorable(int) возвращает true. Идентификаторы, имеющие одинаковый внешний вид, могут быть различными.
Например, идентификаторы, состоящие из одиночных букв LATIN CAPITAL LETTER A (A, \u0041), LATIN SMALL LETTER A (a, \u0061), GREEK CAPITAL LETTER ALPHA (A, \u0391), CYRILLIC SMALL LETTER A (a, \u0430) и MATHEMATICAL BOLD ITALIC SMALL A (a, \ud835\udc82), все разные.
Композиционные символы Unicode отличаются от их канонически эквивалентных разложенных символов. Например, LATIN CAPITAL LETTER A ACUTE (Á, \u00c1) отличается от LATIN CAPITAL LETTER A (A, \u0041), за которым сразу следует NON-SPACING ACUTE (´, \u0301) в идентификаторах. См. Стандарт Unicode, раздел 3.11 «Формы нормализации».
Примеры идентификаторов:
-
String -
i3 -
αρετη
-
MAX_VALUE -
isLetterOrDigit
Идентификатор никогда не имеет такого же написания (последовательности символов Unicode), как зарезервированное ключевое слово (§3.9), булево значение (§3.10.3) или значение null (§3.10.8), из-за правил токенизации (§3.5). Однако идентификатор может иметь такое же написание, как контекстное ключевое слово, поскольку токенизация последовательности входных символов как идентификатора или контекстного ключевого слова зависит от того, где эта последовательность встречается в программе.
Для облегчения распознавания контекстных ключевых слов синтаксическая грамматика (§2.3) иногда запрещает определённые идентификаторы, определяя производство, которое принимает только подмножество идентификаторов. Подмножества следующие:
ТипИдентификатор используется при объявлении классов, интерфейсов и параметров типа (§8.1, §9.1, §4.4), и при ссылке на типы (§6.5). Например, имя класса должно быть ТипИдентификатор, поэтому недопустимо объявлять класс с именем permits, record, sealed, var или yield.
НеквалифицированныйИдентификаторМетода используется, когда выражение вызова метода ссылается на метод по его простому имени (§6.5.7.1). Поскольку термин yield исключён из НеквалифицированныйИдентификаторМетода, любой вызов метода с именем yield должен быть квалифицирован, тем самым отличая вызов от оператора yield (§14.21).
51 последовательность символов, образованных из символов ASCII, зарезервированы для использования в качестве ключевых слов и не могут использоваться в качестве идентификаторов (§3.8). Ещё 16 последовательностей символов, также образованных из символов ASCII, могут интерпретироваться как ключевые слова или другие токены, в зависимости от контекста, в котором они появляются.
abstract continue for new switchassert default if package synchronizedboolean do goto private thisbreak double implements protected throwbyte else import public throwscase enum instanceof return transientcatch extends int short trychar final interface static voidclass finally long strictfp volatileconst float native super while_(underscore)
exports opens requires usesmodule permits sealed varnon-sealed provides to withopen record transitive yield
Ключевые слова const и goto зарезервированы, даже если они в настоящее время не используются. Это может позволить компилятору Java создавать более информативные сообщения об ошибках, если эти ключевые слова C++ некорректно появятся в программах.
Ключевое слово strictfp устарело и не должно использоваться в новом коде.
Ключевое слово _ (подчеркивание) зарезервировано для возможного будущего использования в объявлениях параметров.
true и false не являются ключевыми словами, а являются булевыми литералами (§3.10.3).
null не является ключевым словом, а является литералом null (§3.10.8).
Во время сокращения входных символов до входных элементов (§3.5), последовательность входных символов, которая по смыслу соответствует контекстному ключевому слову, сокращается до контекстного ключевого слова только в том случае, если выполняются оба следующих условия:
-
Последовательность распознается как терминал, указанный в соответствующем контексте синтаксической грамматики (§2.3), как следует:
-
Для
moduleиopen, когда распознается как терминал в ModuleDeclaration (§7.7). -
Для
exports,opens,provides,requires,to,usesиwith, когда распознается как терминал в ModuleDirective. -
Для
transitive, когда распознается как терминал в RequiresModifier.Например, распознавание последовательности
requirestransitive;не использует RequiresModifier, поэтому терминtransitiveсокращается здесь до идентификатора, а не контекстного ключевого слова. -
Для
var, когда распознается как терминал в LocalVariableType (§14.4) или LambdaParameterType (§15.27.1).В других контекстах попытка использовать
varв качестве идентификатора приведет к ошибке, потому чтоvarне является TypeIdentifier (§3.8). -
Для
yield, когда распознается как терминал в YieldStatement (§14.21).В других контекстах попытка использовать
yieldв качестве идентификатора приведет к ошибке, потому чтоyieldне является ни TypeIdentifier, ни UnqualifiedMethodIdentifier. -
Для
record, когда распознается как терминал в RecordDeclaration (§8.10). -
Для
non-sealed,permitsиsealed, когда распознается как терминал в NormalClassDeclaration (§8.1) или NormalInterfaceDeclaration (§9.1).
-
-
Последовательность не предшествует непосредственно и не следует непосредственно за входным символом, соответствующим JavaLetterOrDigit.
В общем случае, случайное пропущение пробелов в исходном коде приведет к тому, что последовательность входных символов будет распознана как идентификатор из-за правила «наиболее длинного возможного перевода» (§3.2). Например, последовательность из двенадцати входных символов p u b l i c s t a t i c всегда распознается как идентификатор publicstatic, а не как зарезервированные ключевые слова public и static. Если предполагается два токена, их необходимо разделить пробелами или комментарием.
Указанное выше правило работает совместно с правилом «наиболее длинного возможного перевода», чтобы получить интуитивный результат в контекстах, где могут появляться контекстные ключевые слова. Например, последовательность из одиннадцати входных символов v a r f i l e n a m e обычно распознается как идентификатор varfilename, но в объявлении локальной переменной первые три входных символа предварительно распознаются как контекстное ключевое слово var по первому условию правила выше. Однако было бы запутанно пропустить отсутствие пробелов при распознавании следующих восьми входных символов как идентификатора filename. (Это означало бы, что последовательность подвергается различной лексемизации в различных контекстах: идентификатор в большинстве контекстов, но контекстное ключевое слово и идентификатор в объявлениях локальных переменных.) Соответственно, второе условие предотвращает распознавание контекстного ключевого слова var по той причине, что непосредственно следующий входной символ f является JavaLetterOrDigit. Последовательность v a r f
i l e n a m e поэтому распознается как идентификатор varfilename в объявлении локальной переменной.
В качестве ещё одного примера внимательного распознавания контекстных ключевых слов рассмотрим последовательность из 15 входных символов n o n - s e a l
e d c l a s s. Эта последовательность обычно преобразуется в три токена — идентификатор non, оператор - и идентификатор sealedclass — но в объявлении обычного класса, где выполняется первое условие, первые десять входных символов предварительно распознаются как контекстное ключевое слово non-sealed. Чтобы избежать преобразования последовательности в два ключевых слова (non-sealed и class) вместо трёх неключевых токенов, и чтобы избежать вознаграждения программиста за пропуск пробелов перед class, второе условие предотвращает распознавание контекстного ключевого слова. Последовательность n o n - s e a l e d c l a s s поэтому распознаётся как три токена в объявлении класса.
В приведенном выше правиле первое условие зависит от деталей синтаксической грамматики, но компилятор языка программирования Java может реализовать это правило без полного разбора входной программы. Например, можно использовать эвристику для отслеживания контекстного состояния токенизатора, при условии, что эвристика гарантирует, что допустимые использования контекстных ключевых слов токенизируются как ключевые слова, а допустимые использования идентификаторов — как идентификаторы. В качестве альтернативы компилятор может всегда токенизировать контекстное ключевое слово как идентификатор, оставив позднее определение особых применений этих идентификаторов.
A литерал — это представление значения примитивного типа в исходном коде (§4.2), типа String (§4.3.3) или типа null (§4.1).
Целочисленный литерал может быть представлен в десятичной (основание 10), шестнадцатеричной (основание 16), восьмеричной (основание 8) или двоичной (основание 2) форме.
l L Целочисленный литерал имеет тип long, если он имеет суффикс из ASCII буквы L или l (ell); в противном случае его тип — int (§4.2.1).
Суффикс L предпочтительнее, так как букву l (ell) часто трудно отличить от цифры 1 (один).
Подчеркивания разрешены в качестве разделителей между цифрами, обозначающими целое число.
В шестнадцатеричном или двоичном литерале целое число обозначается только цифрами после символов 0x или 0b и перед любым суффиксом типа. Поэтому подчеркивания не могут появляться сразу после 0x или 0b, или после последней цифры в числе.
В десятичном или восьмеричном литерале целое число обозначается всеми цифрами в литерале перед любым суффиксом типа. Поэтому подчеркивания не могут появляться перед первой цифрой или после последней цифры в числе. Подчеркивания могут появляться после начальной 0 в восьмеричном числе (поскольку 0 — это цифра, обозначающая часть целого числа) и после начальной ненулевой цифры в ненулевом десятичном литерале.
Десятичное число — это либо одиночная ASCII цифра 0, представляющая целое число ноль, либо состоит из ASCII цифры от 1 до 9, за которой необязательно следуют одна или несколько ASCII цифр от 0 до 9, перемежающиеся подчеркиваниями, представляющими положительное целое число.
1 2 3 4 5 6 7 8 9 _ {_} Шестнадцатеричное число состоит из ведущих ASCII символов 0x или 0X, за которыми следуют одна или несколько ASCII шестнадцатеричных цифр, перемежающихся подчеркиваниями, и может представлять положительное, нулевое или отрицательное целое число.
Шестнадцатеричные цифры со значениями от 10 до 15 представлены ASCII буквами a до f или A до F соответственно; каждая буква, используемая как шестнадцатеричная цифра, может быть заглавной или строчной.
0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F Производство ШестнадцатеричнаяЦифра выше взято из §3.3.
Восьмеричное число состоит из ASCII цифры 0, за которой следуют одна или несколько ASCII цифр от 0 до 7, перемежающиеся подчеркиваниями, и может представлять положительное, нулевое или отрицательное целое число.
0 1 2 3 4 5 6 7 Обратите внимание, что восьмеричные числа всегда состоят из двух или более цифр, так как 0 в одиночку всегда считается десятичным числом — не имеет значения на практике, поскольку числа 0, 00 и 0x0 представляют одно и то же целое число.
Двоичное число состоит из ведущих ASCII символов 0b или 0B, за которыми следуют одна или несколько ASCII цифр 0 или 1, перемежающиеся подчеркиваниями, и может представлять положительное, нулевое или отрицательное целое число.
0 1 Наибольшая десятичная литерал типа int составляет 2147483648 (231).
Все десятичные литералы от 0 до 2147483647 могут встречаться там, где может встречаться int литерал. Десятичная литерал 2147483648 может встречаться только в качестве операнда унарного минуса - (§15.15.4).
Если десятичная литерал 2147483648 встречается где-либо кроме как в качестве операнда унарного минуса, или если десятичная литерал типа int больше, чем 2147483648 (231), то это ошибка времени компиляции.
Наибольшие положительные шестнадцатеричные, восьмеричные и двоичные литералы типа int, каждый из которых представляет десятичное значение 2147483647 (231-1), соответственно:
-
0x7fff_ffff, -
0177_7777_7777, и -
0b0111_1111_1111_1111_1111_1111_1111_1111
Наиболее отрицательные шестнадцатеричные, восьмеричные и двоичные литералы типа int, каждый из которых представляет десятичное значение -2147483648 (-231), соответственно:
-
0x8000_0000, -
0200_0000_0000, и -
0b1000_0000_0000_0000_0000_0000_0000_0000
Следующие шестнадцатеричные, восьмеричные и двоичные литералы представляют десятичное значение -1:
-
0xffff_ffff, -
0377_7777_7777, и -
0b1111_1111_1111_1111_1111_1111_1111_1111
Ошибка времени компиляции, если шестнадцатеричный, восьмеричный или двоичный int литерал не умещается в 32 бита.
Наибольший десятичный литерал типа long составляет 9223372036854775808L (263).
Все десятичные литералы от 0L до 9223372036854775807L могут встречаться там, где может встречаться long литерал. Десятичная литерал 9223372036854775808L может встречаться только в качестве операнда унарного минуса - (§15.15.4).
Ошибка времени компиляции, если десятичная литерал 9223372036854775808L встречается где-либо, кроме как в качестве операнда унарного минуса; или если десятичная литерал типа long больше, чем 9223372036854775808L (263).
Наибольшие положительные шестнадцатеричные, восьмеричные и двоичные литералы типа long, каждый из которых представляет десятичное значение 9223372036854775807L (263-1), соответственно:
-
0x7fff_ffff_ffff_ffffL, -
07_7777_7777_7777_7777_7777L, и -
0b0111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111L
Наиболее отрицательные шестнадцатеричные, восьмеричные и двоичные литералы типа long, каждый из которых представляет десятичное значение -9223372036854775808L (-263), соответственно:
-
0x8000_0000_0000_0000L, и -
010_0000_0000_0000_0000_0000L, и -
0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000L
Следующие шестнадцатеричные, восьмеричные и двоичные литералы представляют десятичное значение -1L:
-
0xffff_ffff_ffff_ffffL, -
017_7777_7777_7777_7777_7777L, и -
0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111L
Ошибка времени компиляции, если шестнадцатеричный, восьмеричный или двоичный long литерал не умещается в 64 бита.
Примеры int литералов:
0 2 0372 0xDada_Cafe 1996 0x00_FF__00_FF
Примеры long литералов:
0l 0777L 0x100000000L 2_147_483_648L 0xC0B0L
Вещественный литерал состоит из следующих частей: целая часть, десятичная или шестнадцатеричная точка (представленная символом ASCII точки), дробная часть, экспонента и суффикс типа.
Вещественный литерал может быть представлен в десятичной (основание 10) или шестнадцатеричной (основание 16) системе.
Для десятичных вещественных литералов требуется хотя бы одна цифра (в целой или дробной части) и либо десятичная точка, либо экспонента, либо суффикс типа float. Все остальные части являются необязательными. Экспонента, если присутствует, обозначается символами ASCII e или E, за которыми следует необязательно со знаком целое число.
Для шестнадцатеричных вещественных литералов требуется хотя бы одна цифра (в целой или дробной части), и экспонента обязательна, а суффикс типа float необязателен. Экспонента обозначается символами ASCII p или P, за которыми следует необязательно со знаком целое число.
Подчеркивания разрешены в качестве разделителей между цифрами, обозначающими целую часть, и между цифрами, обозначающими дробную часть, и между цифрами, обозначающими экспоненту.
e E + - f F d D p P Вещественный литерал имеет тип float, если он имеет суффикс с символами ASCII F или f; в противном случае его тип является double, и он может необязательно иметь суффикс с символами ASCII D или d.
Элементы типов float и double представляют собой значения, которые могут быть представлены в формате чисел с плавающей точкой IEEE 754 binary32 и IEEE 754 binary64 соответственно (§4.2.3).
Подробности правильного преобразования входной строки Unicode, представляющей число с плавающей точкой, во внутреннее двоичное представление с плавающей точкой IEEE 754 описаны для методов valueOf класса Float и класса Double пакета java.lang.
Наибольшие и наименьшие положительные литералы типа float представлены следующим образом:
-
Наибольшее положительное конечное значение
floatчисленно равно (2 - 2-23) ⋅ 2127.Наиболее короткое десятичное представление, которое округляется до этого значения, равно
3.4028235e38f.Шестнадцатеричное представление этого значения равно
0x1.fffffeP+127f. -
Наименьшее положительное конечное ненулевое значение
floatчисленно равно 2-149.Наиболее короткое десятичное представление, которое округляется до этого значения, равно
1.4e-45f.Два шестнадцатеричных представления этого значения равны
0x0.000002P-126fи0x1.0P-149f.
Наибольшие и наименьшие положительные литералы типа double представлены следующим образом:
-
Наибольшее положительное конечное значение
doubleчисленно равно (2 - 2-52) ⋅ 21023.Наиболее короткое десятичное представление, которое округляется до этого значения, равно
1.7976931348623157e308.Шестнадцатеричное представление этого значения равно
0x1.f_ffff_ffff_ffffP+1023. -
Наименьшее положительное конечное ненулевое значение
doubleчисленно равно 2-1074.Наиболее короткое десятичное представление, которое округляется до этого значения, равно
4.9e-324.Два шестнадцатеричных представления этого значения равны
0x0.0_0000_0000_0001P-1022и0x1.0P-1074.
Это ошибка компиляции, если ненулевой вещественный литерал слишком велик, так что при округленном преобразовании во внутреннее представление он становится бесконечностью IEEE 754.
Программа может представлять бесконечности без ошибки компиляции, используя константные выражения, такие как 1f/0f или -1d/0d, или используя предопределённые константы POSITIVE_INFINITY и NEGATIVE_INFINITY классов Float и Double.
Это ошибка компиляции, если ненулевой вещественный литерал слишком мал, так что при округленном преобразовании во внутреннее представление он становится нулём.
Ошибка компиляции не возникает, если ненулевой вещественный литерал имеет небольшое значение, которое при округленном преобразовании во внутреннее представление становится ненулевым числом с малой мантиссой.
Предопределённые константы, представляющие значения «не число», определены в классах Float и Double как Float.NaN и Double.NaN.
Примеры float литералов:
1e1f 2.f .3f 0f 3.14f 6.022137e+23f
Примеры double литералов:
1e1 2. .3 0.0 3.14 1e-9d 1e137
Тип boolean имеет два значения, представленные булевыми литералами true и false, образованными из символов ASCII.
true false Булевый литерал всегда имеет тип boolean (§4.2.5).
Литерал символа выражается как символ или последовательность управляющих символов (§3.10.7), заключённые в одинарные кавычки ASCII. (Символ одинарной кавычки, или апострофа, является \u0027.)
Литерал символа всегда имеет тип char (§4.2.1).
Содержание литерала символа — это SingleCharacter или EscapeSequence, идущие сразу после открывающей '.
Ошибка компиляции, если символ, следующий за содержанием, не является '.
Ошибка компиляции, если после открывающей ' и до закрывающей ' встречается разделитель строки (§3.4).
Символы CR и LF никогда не являются Входным символом; каждый из них рассматривается как разделитель строки, поэтому не может встречаться в литерале символа, даже в последовательности управляющих символов \ разделитель строки.
Символ, представленный литералом символа — это содержание литерала символа с интерпретированной последовательностью управляющих символов, как будто выполняется String.translateEscapes на содержимом.
Литералы символов могут представлять только единицы кодировки UTF-16 (§3.1), то есть ограничены значениями от \u0000 до \uffff. Дополнительные символы должны быть представлены либо как пара суррогатов в последовательности char, либо как целое число, в зависимости от API, с которым они используются.
Ниже приведены примеры char литералов:
-
'a' -
'%' -
'\t' -
'\\' -
'\'' -
'\u03a9' -
'\uFFFF' -
'\177' -
'™'
Поскольку эскейпы Unicode обрабатываются очень рано, неправильно писать '\u000a' для литерала символа, значение которого — перевод строки (LF); эскейп Unicode \u000a преобразуется в фактический перевод строки на шаге 1 трансляции (§3.3), а перевод строки становится разделителем строки на шаге 2 (§3.4), поэтому литерал символа некорректен на шаге 3. Вместо этого следует использовать последовательность управляющих символов '\n'. Аналогично, неправильно писать '\u000d' для литерала символа, значение которого — возврат каретки (CR). Используйте вместо этого '\r'. Наконец, невозможно написать '\u0027' для литерала символа, содержащего апостроф (').
В C и C++ литерал символа может содержать представления более одного символа, но значение такого литерала символа определяется реализацией. В языке программирования Java литерал символа всегда представляет ровно один символ.
Литерал строки состоит из нуля или более символов, заключённых в двойные кавычки. Символы, такие как новые строки, могут быть представлены последовательностями управляющих символов (§3.10.7).
Литерал строки всегда имеет тип String (§4.3.3).
Содержание литерала строки — это последовательность символов, начинающаяся сразу после открывающей " и заканчивающаяся сразу перед соответствующей закрывающей ".
Ошибка компиляции, если после открывающей " и перед соответствующей закрывающей " встречается разделитель строки (§3.4).
Символы CR и LF никогда не являются Входным символом; каждый из них рассматривается как разделитель строки, поэтому не может встречаться в строковом литерале, даже в последовательности управляющих символов \ разделитель строки.
Строка, представленная строковым литералом, — это содержание строкового литерала с интерпретированной каждой последовательностью управляющих символов, как будто выполняется String.translateEscapes на содержимом.
Ниже приведены примеры строковых литералов:
"" // the empty string
"\"" // a string containing " alone
"This is a string" // a string containing 16 characters
"This is a " + // actually a string-valued constant expression,
"two-line string" // formed from two string literals
Поскольку эскейпы Unicode обрабатываются очень рано, неправильно писать "\u000a" для строкового литерала, содержащего одиночный перевод строки (LF); эскейп Unicode \u000a преобразуется в фактический перевод строки на шаге 1 трансляции (§3.3), а перевод строки становится разделителем строки на шаге 2 (§3.4), поэтому строковый литерал некорректен на шаге 3. Вместо этого следует использовать последовательность управляющих символов "\n". Аналогично, неправильно писать "\u000d" для строкового литерала, содержащего одиночную возврат каретки (CR). Используйте вместо этого "\r". Наконец, невозможно написать "\u0022" для строкового литерала, содержащего двойную кавычку (").
Длинный строковый литерал всегда можно разбить на более короткие части и записать как (возможно, скобочное) выражение, используя оператор конкатенации строк + (§15.18.1).
Во время выполнения строковый литерал является ссылкой на экземпляр класса String (§4.3.3), который обозначает строку, представленную строковым литералом.
Кроме того, строковый литерал всегда ссылается на один и тот же экземпляр класса String. Это потому, что строковые литералы — или, в более общем случае, строки, которые являются значениями константных выражений (§15.29) — «интернированы», чтобы совместно использовать уникальные экземпляры, как будто выполняется метод String.intern (§12.5).
Пример 3.10.5-1. Литералы строк
Программа, состоящая из единицы компиляции (§7.3):
package testPackage;
class Test {
public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.println(hello == "Hello");
System.out.println(Other.hello == hello);
System.out.println(other.Other.hello == hello);
System.out.println(hello == ("Hel"+"lo"));
System.out.println(hello == ("Hel"+lo));
System.out.println(hello == ("Hel"+lo).intern());
}
}
class Other { static String hello = "Hello"; }
и единицы компиляции:
package other;
public class Other { public static String hello = "Hello"; }
выводит:
true true true true false true
Этот пример иллюстрирует шесть пунктов:
-
Строковые литералы в одном классе и пакете представляют ссылки на один и тот же объект
String(§4.3.1). -
Строковые литералы в разных классах в одном пакете представляют ссылки на один и тот же объект
String. -
Строковые литералы в разных классах в разных пакетах также представляют ссылки на один и тот же объект
String. -
Строки, конкатенированные из константных выражений (§15.29), вычисляются во время компиляции и затем обрабатываются так, как будто они были литералами.
-
Строки, вычисленные путём конкатенации во время выполнения, создаются заново и поэтому различны.
-
Результат явного интернирования вычисленной строки — это тот же самый объект
String, что и любой существующий строковый литерал с тем же самым содержимым.
Текстовый блок состоит из нуля или более символов, заключённых в открывающие и закрывающие разделители. Символы могут быть представлены с помощью последовательностей escape (§3.10.7), но символы новой строки и двойной кавычки, которые должны быть представлены с помощью последовательностей escape в строковой литерале (§3.10.5), могут быть представлены непосредственно в текстовом блоке.
Следующие продукционные правила из §3.3, §3.4 и §3.6 приведены здесь для удобства:
символ ASCII HT, также известный как "горизонтальная табуляция"
символ ASCII FF, также известный как "формат страницы"
Перенос строки
символ ASCII CR, также известный как "возврат каретки"
символ ASCII CR, за которым следует символ ASCII LF
Текстовый блок всегда является строкой типа String (§4.3.3).
Открывающий разделитель — это последовательность, начинающаяся с трёх символов двойной кавычки ("""), продолжающаяся нулём или более пробелами, табуляциями и символами перевода страницы, и завершающаяся символом перевода строки.
Закрывающий разделитель — это последовательность из трёх символов двойной кавычки.
Содержимое текстового блока — это последовательность символов, начинающаяся сразу после символа перевода строки открывающего разделителя и заканчивающаяся непосредственно перед первой двойной кавычкой закрывающего разделителя.
В отличие от строковой литералы (§3.10.5), появление символа перевода строки в содержимом текстового блока не является ошибкой на этапе компиляции.
Пример 3.10.6-1. Текстовые блоки
Когда требуются многострочные строки, текстовый блок обычно более удобочитаем, чем конкатенация строковых литералов. Например, сравните эти альтернативные представления фрагмента HTML:
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>\n";
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
Ниже приведены примеры текстовых блоков:
class Test {
public static void main(String[] args) {
// The six characters w i n t e r
String season = """
winter""";
// The seven characters w i n t e r LF
String period = """
winter
""";
// The ten characters H i , SP " B o b " LF
String greeting = """
Hi, "Bob"
""";
// The eleven characters H i , LF SP " B o b " LF
String salutation = """
Hi,
"Bob"
""";
// The empty string (zero length)
String empty = """
""";
// The two characters " LF
String quote = """
"
""";
// The two characters \ LF
String backslash = """
\\
""";
}
}
Использование последовательностей escape \n и \" для представления символа новой строки и символа двойной кавычки соответственно допускается в текстовом блоке, хотя обычно не требуется. Исключение составляет случай, когда встречаются три последовательных символа двойной кавычки, которые не предназначены для закрывающего разделителя """ - в этом случае необходимо экранировать как минимум один из символов двойной кавычки, чтобы избежать имитации закрывающего разделителя.
Пример 3.10.6-2. Последовательности escape в текстовых блоках
В следующей программе значение переменной story было бы менее удобочитаемым, если бы отдельные символы двойной кавычки были экранированы:
class Story1 {
public static void main(String[] args) {
String story = """
"When I use a word," Humpty Dumpty said,
in rather a scornful tone, "it means just what I
choose it to mean - neither more nor less."
"The question is," said Alice, "whether you
can make words mean so many different things."
"The question is," said Humpty Dumpty,
"which is to be master - that's all."
""";
}
}
Если программа изменена таким образом, что закрывающий разделитель помещается в последней строке содержимого, то возникает ошибка, поскольку первые три последовательных символа двойной кавычки в последней строке преобразуются (§3.2) в закрывающий разделитель """, и таким образом остаётся лишний символ двойной кавычки:
class Story2 {
public static void main(String[] args) {
String story = """
"When I use a word," Humpty Dumpty said,
in rather a scornful tone, "it means just what I
choose it to mean - neither more nor less."
"The question is," said Alice, "whether you
can make words mean so many different things."
"The question is," said Humpty Dumpty,
"which is to be master - that's all.""""; // error
}
}
Ошибка можно избежать, экранировав последний символ двойной кавычки в содержимом:
class Story3 {
public static void main(String[] args) {
String story = """
"When I use a word," Humpty Dumpty said,
in rather a scornful tone, "it means just what I
choose it to mean - neither more nor less."
"The question is," said Alice, "whether you
can make words mean so many different things."
"The question is," said Humpty Dumpty,
"which is to be master - that's all.\""""; // OK
}
}
Если текстовый блок предназначен для обозначения другого текстового блока, рекомендуется экранировать первый символ двойной кавычки встроенных открывающих и закрывающих разделителей:
class Code {
public static void main(String[] args) {
String text = """
The quick brown fox jumps over the lazy dog
""";
String code =
"""
String text = \"""
The quick brown fox jumps over the lazy dog
\""";
""";
}
}
Строка, представленная текстовым блоком, не является буквальной последовательностью символов в содержимом. Вместо этого строка, представленная текстовым блоком, является результатом применения следующих преобразований к содержимому в заданном порядке:
-
Символы переноса строки нормализуются до символа ASCII LF следующим образом:
-
Последовательность символа ASCII CR и символа ASCII LF преобразуется в символ ASCII LF.
-
Символ ASCII CR преобразуется в символ ASCII LF.
-
-
Случайные пробелы удаляются, как будто выполняется
String.stripIndentна символах, полученных на шаге 1. -
Последовательности escape интерпретируются, как будто выполняется
String.translateEscapesна символах, полученных на шаге 2.
Когда в этом спецификации говорится, что текстовый блок содержит определённый символ или последовательность символов, или что определённый символ или последовательность символов находятся в текстовом блоке, это означает, что строка, представленная текстовым блоком (в отличие от буквальной последовательности символов в содержимом), содержит этот символ или последовательность символов.
Пример 3.10.6-3. Порядок преобразований содержимого текстового блока
Интерпретация последовательностей escape в последнюю очередь позволяет программистам использовать \n, \f и \r для вертикального форматирования строки без влияния на нормализацию символов переноса строки и использовать \b и \t для горизонтального форматирования строки без влияния на удаление случайных пробелов. Например, рассмотрим этот текстовый блок, который упоминает последовательность escape \r (CR):
String html = """
<html>\r
<body>\r
<p>Hello, world</p>\r
</body>\r
</html>\r
""";
Последовательности escape \r интерпретируются только после нормализации символов переноса строки до LF. Используя Unicode-экранирование для визуализации LF (\u000A) и CR (\u000D), и используя | для визуализации левого отступа, строка, представленная текстовым блоком, выглядит следующим образом:
|<html>\u000D\u000A | <body>\u000D\u000A | <p>Hello, world</p>\u000D\u000A | </body>\u000D\u000A |</html>\u000D\u000A
Во время выполнения текстовый блок является ссылкой на экземпляр класса String, который обозначает строку, представленную текстовым блоком.
Более того, текстовый блок всегда ссылается на один и тот же экземпляр класса String. Это потому, что строки, представленные текстовыми блоками, или, более общо, строки, которые являются значениями константных выражений (§15.29), "интернационализированы", чтобы иметь общие уникальные экземпляры, как будто бы выполняется метод String.intern (§12.5).
Пример 3.10.6-4. Блоки текста приводят к String
Блоки текста могут использоваться везде, где разрешено выражение типа String, например, в конкатенации строк (§15.18.1), в вызове методов экземпляров String и в аннотациях с элементами String:
System.out.println("ab" + """
cde
""");
String cde = """
abcde""".substring(2);
String math = """
1+1 equals \
""" + String.valueOf(2);
@Preconditions("""
rate > 0 &&
rate <= MAX_REFRESH_RATE
""")
public void setRefreshRate(int rate) { ... }
В символьных литералах, строковых литералах и блоках текста (§3.10.4, §3.10.5, §3.10.6) последовательности экранирования позволяют представлять некоторые неграфические символы без использования Unicode-экранирования (§3.3), а также символы одинарной и двойной кавычки, и обратной косой черты.
\ b (ввод BS, Unicode \u0008) \ s (пробел SP, Unicode \u0020) \ t (горизонтальная табуляция HT, Unicode \u0009) \ n (перевод строки LF, Unicode \u000a) \ f (формат страницы FF, Unicode \u000c) \ r (возврат каретки CR, Unicode \u000d) \ LineTerminator (продолжение строки, без представления Unicode) \ " (двойная кавычка ", Unicode \u0022) \ ' (одинарная кавычка ', Unicode \u0027) \ \ (обратная косая черта \, Unicode \u005c) OctalEscape (восьмеричное значение, Unicode
\u0000 по \u00ff) 0 1 2 3 4 5 6 7 0 1 2 3 Производство OctalDigit выше взято из §3.10.1. Восьмеричные escapes предоставлены для совместимости с C, но могут выражать только значения Unicode \u0000 по \u00FF, поэтому обычно предпочтительнее использовать Unicode-экранирование.
Если символ, следующий за обратной косой чертой в последовательности экранирования, не является LineTerminator или ASCII b, s, t, n, f, r, ", ', \, 0, 1, 2, 3, 4, 5, 6 или 7, то это ошибка времени компиляции.
Последовательность экранирования в содержании символьного литерала, строкового литерала или блока текста интерпретируется путем замены предшествующих ей символов и последующего символа(ов) одиночным символом, обозначаемым Unicode-экранированием в грамматике EscapeSequence. Последовательность экранирования для продолжения строки не имеет соответствующего Unicode-экранирования, поэтому интерпретируется путем замены ее на пустоту.
Последовательность экранирования для продолжения строки может встречаться в блоке текста, но не может встречаться в символьном или строковом литерале, так как каждый из них запрещает LineTerminator.
Тип null имеет одно значение — нулевую ссылку, представленную литералом null null, который формируется из ASCII-символов.
nullЛитерал null всегда относится к типу null (§4.1).
Двенадцать лексем, образованных из ASCII-символов, являются разделителями (пунктуаторами).
( ) { } [ ] ; , . ... @ :: 38 лексем, образованных из ASCII-символов, являются операторами.
= > < ! ~ ? :->== >= <= != && || ++ --+ - * / & | ^ % << >> >>>+= -= *= /= &= |= ^= %= <<= >>= >>>=
© Oracle and/or its affiliates. All rights reserved.
Licensed under the Oracle Technology Network License Agreement.