Глава 3. Лексическая структура
Содержание
В этой главе описывается лексическая структура языка программирования Java.
Программы написаны на Unicode (§3.1), но для включения любого символа Unicode с использованием только символов ASCII предоставляются лексические преобразования (§3.2), например, с помощью экранирования Unicode (§3.3). Определены разделители строк (§3.4), чтобы поддерживать различные соглашения существующих систем, сохраняя при этом последовательность номеров строк.
Символы Unicode, полученные в результате лексических преобразований, сводятся к последовательности элементов ввода (§3.5), которые представляют пробелы (§3.6), комментарии (§3.7) и токены. Токены — это идентификаторы (§3.8), ключевые слова (§3.9), литералы (§3.10), разделители (§3.11) и операторы (§3.12) синтаксической грамматики.
Программы пишутся с использованием набора символов Unicode. Сведения об этом наборе символов и связанных с ним кодировках можно найти в http://www.unicode.org/.
Платформа Java SE отслеживает стандарт Unicode по мере его развития. Точная версия Unicode, используемая конкретным выпуском, указана в документации класса Character.
Версии языка программирования Java до JDK 1.1 использовали Unicode 1.1.5. Обновления до более новых версий стандарта Unicode произошли в JDK 1.1 (до Unicode 2.0), JDK 1.1.7 (до Unicode 2.1), Java SE 1.4 (до Unicode 3.0), Java SE 5.0 (до Unicode 4.0), Java SE 7 (до Unicode 6.0), Java SE 8 (до Unicode 6.2), Java SE 9 (до Unicode 8.0) и Java SE 11 (до Unicode 10.0).
Изначально стандарт Unicode был разработан как кодировка символов с фиксированной шириной 16 бит. Позднее он был изменён, чтобы позволить использовать символы, представление которых требует более 16 бит. Диапазон допустимых кодовых точек теперь U+0000 до U+10FFFF, используя шестнадцатеричное обозначение U+n. Символы, кодовые точки которых больше U+FFFF, называются дополнительными символами. Для представления всего диапазона символов с использованием только 16-битовых единиц стандарт Unicode определяет кодировку UTF-16. В этой кодировке дополнительные символы представлены парами 16-битовых кодовых единиц, первая из диапазона высоких суррогатов (U+D800 до U+DBFF), вторая — из диапазона низких суррогатов (U+DC00 до U+DFFF). Для символов в диапазоне U+0000 до U+FFFF значения кодовых точек и кодовых единиц UTF-16 совпадают.
Язык программирования Java представляет текст в последовательностях 16-битовых кодовых единиц, используя кодировку UTF-16.
Некоторые API платформы Java SE, в основном в классе Character, используют 32-битовые целые числа для представления кодовых точек как отдельных сущностей. Платформа Java SE предоставляет методы для преобразования между 16-битными и 32-битными представлениями.
В этом спецификации используются термины кодовая точка и кодовая единица UTF-16, когда представление актуально, и общий термин символ, когда представление не имеет значения для обсуждения.
За исключением комментариев (§3.7), идентификаторов и содержимого символьных и строковых литералов (§3.10.4, §3.10.5), все элементы ввода (§3.5) в программе формируются только из символов ASCII (или экранирования Unicode (§3.3), которые приводят к символам ASCII).
ASCII (ANSI X3.4) — это американский стандартный код для обмена информацией. Первые 128 символов кодировки Unicode UTF-16 — это символы ASCII.
Поток исходных символов Unicode преобразуется в последовательность токенов, используя следующие три шага лексического преобразования, которые применяются поочерёдно:
-
Преобразование экранирования Unicode (§3.3) в исходном потоке символов Unicode в соответствующий символ Unicode. Экранирование Unicode в формате
\uxxxx, гдеxxxx— шестнадцатеричное значение, представляет кодовую единицу UTF-16, чья кодировка равнаxxxx. Этот шаг преобразования позволяет выразить любую программу, используя только символы ASCII. -
Преобразование потока Unicode, полученного на шаге 1, в поток входных символов и разделителей строк (§3.4).
-
Преобразование потока входных символов и разделителей строк, полученного на шаге 2, в последовательность элементов ввода (§3.5), которые после удаления пробелов (§3.6) и комментариев (§3.7), составляют токены (§3.5), являющиеся терминальными символами синтаксической грамматики (§2.3).
На каждом шаге используется самое длинное возможное преобразование, даже если результат в конечном итоге не является правильной программой, в то время как другое лексическое преобразование было бы таковым. Существует одно исключение: если лексическое преобразование происходит в контексте типа (§4.11) и поток ввода имеет два или более последовательных > символа, за которыми следует не-> символ, то каждый > символ должен быть преобразован в токен для оператора численного сравнения >.
Вводные символы a--b разделяются на токены (§3.5) как a, --, b, что не является частью любой грамматически корректной программы, даже если разбиение на токены a, -, -, b может быть частью грамматически корректной программы.
Без правила для > символов, два последовательных > скобки в типе, таком как List, будут разделены на токен сдвиг вправо с знаком <List<String>>>>, в то время как три последовательные > скобки в типе, таком как List, будут разделяться на токен сдвига вправо без знака <List<List<String>>>>>>. Хуже того, разбиение на токены четырёх или более последовательных > скобок в типе, таком как List, будет неоднозначным, так как различные комбинации токенов <List<List<List<String>>>>>, >> и >>> могли бы представлять >>>> символов.
Компилятор языка программирования Java ("компилятор Java") сначала распознаёт Unicode-экранирование в своём вводе, преобразуя ASCII-символы \u, за которыми следуют четыре шестнадцатеричных цифры, в единицу кода UTF-16 (§3.1) для указанного шестнадцатеричного значения, и оставляя все остальные символы без изменений. Для представления дополнительных символов требуются два последовательных Unicode-экранирования. Этот этап преобразования приводит к последовательности символов Unicode на входе.
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-символы.
Помимо обработки, подразумеваемой грамматикой, для каждого символа на входе, являющегося обратной косой чертой \, обработка ввода должна учитывать, сколько других \ символов последовательно предшествуют ему, отделяя его от не-\ символа или начала потока ввода. Если это число чётное, то \ может начинать Unicode-экранирование; если нечётное, то \ не может начинать Unicode-экранирование.
Например, исходный ввод "\\u2122=\u2122" приводит к одиннадцати символам " \ \ u 2 1 2 2 = ™ " (\u2122 — это кодировка Unicode символа ™).
Если допустимая \ не следует за u, то она рассматривается как RawInputCharacter и остаётся частью потока экранированного Unicode.
Если допустимая \ следует за u или более чем за одной u, и последняя u не следует за четырьмя шестнадцатеричными цифрами, то происходит ошибка времени компиляции.
Символ, созданный Unicode-экранированием, не участвует в дальнейших Unicode-экранированиях.
Например, исходный ввод \u005cu005a приводит к шести символам \ u 0 0 5 a, потому что 005c — значение Unicode для \. Это не приводит к символу Z, который является Unicode-символом 005a, потому что \, полученная из \u005c, не интерпретируется как начало дальнейшего Unicode-экранирования.
Язык программирования Java определяет стандартный способ преобразования программы, написанной на Unicode, в ASCII, который изменяет программу в форму, обрабатываемую ASCII-инструментами. Преобразование включает преобразование всех Unicode-экранирований в исходном тексте программы в ASCII путём добавления дополнительной u – например, \uxxxx превращается в \uuxxxx – одновременно с преобразованием не-ASCII-символов в исходном тексте в Unicode-экранирования, содержащие по одному u каждый.
Эта преобразованная версия так же приемлема для компилятора Java и представляет точно такую же программу. Точный исходный код Unicode может быть позже восстановлен из этой ASCII-формы путём преобразования каждой последовательности экранирования, где присутствует несколько u, в последовательность символов Unicode с одной u меньше, одновременно преобразуя каждую последовательность экранирования с одной u в соответствующий одиночный символ Unicode.
Компилятор Java должен использовать обозначение \uxxxx в качестве формата вывода для отображения символов Unicode, когда подходящий шрифт недоступен.
Компилятор Java далее делит последовательность символов Unicode на строки, распознавая разделители строк.
символ 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) могут служить для разделения токенов, которые, будучи смежными, могли бы быть проанализированы по-другому. Например, ASCII-символы - и = на входе могут образовывать операторный токен -= (§3.12), только если нет никаких вмещающихся пробелов или комментариев.
В качестве особой уступки для совместимости с некоторыми операционными системами, символ ASCII SUB (\u001a, или control-Z) игнорируется, если это последний символ в потоке экранированного ввода.
Рассмотрим два токена x и y в результирующем потоке ввода. Если x предшествует y, то мы говорим, что x находится слева от y, и что y находится справа от x.
Например, в этом простом фрагменте кода:
class Empty {
}
мы говорим, что токен } находится справа от токена {, даже если он появляется в этом двумерном представлении вниз и влево от токена {. Эта конвенция относительно использования слов "слева" и "справа" позволяет нам говорить, например, о правом операнде бинарного оператора или о левой части присваивания.
Пробелы определяются как ASCII-пробел, табуляция, символ перевода страницы и разделители строк (§3.4).
Существует два вида комментариев:
-
/*текст*/Традиционный комментарий: весь текст от символов ASCII
/*до символов ASCII*/игнорируется (как в C и C++). -
//текстКомментарий в конце строки: весь текст от символов ASCII
//до конца строки игнорируется (как в C++).
Эти правила подразумевают все следующие свойства:
-
Комментарии не вложены.
-
/*и*/не имеют особого значения в комментариях, начинающихся с//. -
//не имеет особого значения в комментариях, начинающихся с/*или/**.
В результате, следующий текст является одним полным комментарием:
/* this comment /* // /** ends here: */
Лексическая грамматика подразумевает, что комментарии не встречаются внутри символьных (§3.10.4) или строковых (§3.10.5) литералов.
Идентификатор — это последовательность неограниченной длины символов 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). Символ доллара должен использоваться только в автоматически сгенерированном исходном коде или, редко, для доступа к существующим именам в старых системах. Подчёркивание может использоваться в идентификаторах, состоящих из двух или более символов, но не может использоваться в качестве односимвольного идентификатора из-за того, что является ключевым словом.
К "цифрам Java" относятся ASCII цифры 0-9 (\u0030-\u0039).
Буквы и цифры могут быть взяты из всего набора символов Unicode, который поддерживает большинство письменных систем, используемых в мире сегодня, включая большие наборы для китайского, японского и корейского языков. Это позволяет программистам использовать идентификаторы в своих программах, написанных на родных языках.
Идентификатор не может иметь такое же написание (последовательность символов Unicode), как ключевое слово (§3.9), булево значение (§3.10.3) или нулевое значение (§3.10.7), в противном случае возникает ошибка компиляции.
Два идентификатора одинаковы только если, после игнорирования игнорируемых символов, идентификаторы имеют одинаковый символ 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
Идентификатор типа — это идентификатор, не являющийся последовательностью символов var.
Идентификаторы типов используются в определенных контекстах, связанных с объявлением или использованием типов. Например, имя класса должно быть TypeIdentifier, поэтому объявление класса с именем var недопустимо (§8.1).
51 последовательность символов, образованных из букв ASCII, зарезервированы для использования в качестве ключевых слов и не могут использоваться в качестве идентификаторов (§3.8).
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)
Ключевые слова const и goto зарезервированы, даже если они в настоящее время не используются. Это может позволить компилятору Java создавать более информативные сообщения об ошибках, если эти ключевые слова C++ неправильно появятся в программах.
Иногда неправильно предполагается, что различные последовательности символов являются ключевыми словами:
-
trueиfalseне являются ключевыми словами, а скорее булевыми литералами (§3.10.3). -
nullне является ключевым словом, а скорее нулевым литералом (§3.10.7). -
varне является ключевым словом, а скорее идентификатором со специальным значением, как тип объявления локальной переменной (§14.4, §14.14.1, §14.14.2, §14.20.3) и тип формального параметра лямбды (§15.27.1).
Ещё десять последовательностей символов являются зарезервированными ключевыми словами: open, module, requires, transitive, exports, opens, to, uses, provides и with. Эти последовательности символов распознаются как ключевые слова только в тех случаях, когда они появляются как терминалы в производных ModuleDeclaration, ModuleDirective и RequiresModifier (§7.7). В остальных случаях они распознаются как идентификаторы для обеспечения совместимости с программами, написанными до введения зарезервированных ключевых слов. Существует одно исключение: непосредственно справа от последовательности символов requires в производной ModuleDirective последовательность символов transitive распознаётся как ключевое слово, если за ней не следует разделитель, в противном случае она распознаётся как идентификатор.
A литерал — это представление значения примитивного типа в исходном коде (§4.2), типа String (§4.3.3) или типа null (§4.1).
Целочисленная литерал может быть представлена в десятичной (основание 10), шестнадцатеричной (основание 16), восьмеричной (основание 8) или двоичной (основание 2) форме.
l L Целочисленная литерал имеет тип long, если она имеет суффикс с латинской буквой 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 (§4.2.3).
Элементы типов float и double представляют собой те значения, которые могут быть представлены с помощью 32-битного одноточного и 64-битного двойного точного форматов чисел с плавающей точкой IEEE 754 соответственно.
Подробное описание правильного преобразования входных данных из строкового представления числа с плавающей точкой в Юникоде во внутреннее представление числа с плавающей точкой в формате IEEE 754 приведено для методов valueOf класса Float и класса Double пакета java.lang.
Наибольший положительный конечный литерал типа float равен 3.4028235e38f.
Наименьший положительный конечный ненулевой литерал типа float равен 1.40e-45f.
Наибольший положительный конечный литерал типа double равен 1.7976931348623157e308.
Наименьший положительный конечный ненулевой литерал типа double равен 4.9e-324.
Если ненулевой литерал с плавающей точкой слишком велик, так что при округленном преобразовании в его внутреннее представление он становится бесконечностью IEEE 754, то возникает ошибка во время компиляции.
Программа может представлять бесконечности без возникновения ошибки во время компиляции, используя константные выражения, такие как 1f/0f или -1d/0d, или используя предварительно определённые константы POSITIVE_INFINITY и NEGATIVE_INFINITY классов Float и Double.
Если ненулевой литерал с плавающей точкой слишком мал, так что при округленном преобразовании в его внутреннее представление он становится нулём, то возникает ошибка во время компиляции.
Ошибка во время компиляции не возникает, если ненулевой литерал с плавающей точкой имеет малое значение, которое при округленном преобразовании в его внутреннее представление становится ненулевым денермализованным числом.
Предварительно определённые константы, представляющие значения Не Число (NaN), определены в классах 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.6), заключённые в одинарные кавычки ASCII. (Символ одинарной кавычки или апострофа – это \u0027.)
См. §3.10.6 для определения EscapeSequence.
Литералы символов могут представлять только единицы кодирования UTF-16 (§3.1), т.е. они ограничены значениями от \u0000 до \uffff. Дополнительные символы должны быть представлены либо как пара суррогатов в последовательности char, либо как целое число, в зависимости от API, с которым они используются.
Литерал символа всегда имеет тип char (§4.2.1).
Ошибка компиляции, если символ, следующий за SingleCharacter или EscapeSequence, отличается от '.
Ошибка компиляции, если разделитель строки (§3.4) появляется после открывающей ' и перед закрывающей '.
Как указано в §3.4, символы CR и LF никогда не являются InputCharacter; каждый из них распознаётся как LineTerminator.
Ниже приведены примеры литералов char:
-
'a' -
'%' -
'\t' -
'\\' -
'\'' -
'\u03a9' -
'\uFFFF' -
'\177' -
'™'
Поскольку эскейпы Unicode обрабатываются очень рано, неверно писать '\u000a' для литерала символа, значение которого — перевод строки (LF); эскейп Unicode \u000a преобразуется в фактический перевод строки на этапе 1 (§3.3), а перевод строки становится LineTerminator на этапе 2 (§3.4), поэтому литерал символа недействителен на этапе 3. Вместо этого следует использовать последовательность управляющих символов '\n' (§3.10.6). Аналогично, неверно писать '\u000d' для литерала символа, значение которого — возврат каретки (CR). Вместо этого используйте '\r'.
В C и C++ литерал символа может содержать представление более одного символа, но значение такого литерала символа определяется реализацией. В языке программирования Java литерал символа всегда представляет ровно один символ.
Строковый литерал состоит из нуля или более символов, заключённых в двойные кавычки. Символы могут быть представлены последовательностями управляющих символов (§3.10.6) — одна последовательность управляющих символов для символов в диапазоне U+0000 до U+FFFF, две последовательности управляющих символов для суррогатных единиц кодирования UTF-16 символов в диапазоне U+010000 до U+10FFFF.
См. §3.10.6 для определения EscapeSequence.
Строковый литерал всегда имеет тип String (§4.3.3).
Ошибка компиляции, если разделитель строки появляется после открывающей " и перед закрывающей соответствующей ".
Как указано в §3.4, символы CR и LF никогда не являются InputCharacter; каждый из них распознаётся как LineTerminator.
Длинный строковый литерал всегда можно разбить на более короткие фрагменты и записать как (возможно, заключённое в скобки) выражение с использованием оператора конкатенации строк + (§15.18.1).
Ниже приведены примеры строковых литералов:
"" // 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), а перевод строки становится LineTerminator на этапе 2 (§3.4), поэтому строковый литерал недействителен на этапе 3. Вместо этого следует написать "\n" (§3.10.6). Аналогично, неверно писать "\u000d" для строкового литерала, содержащего единственную возврат каретки (CR). Вместо этого используйте "\r". Наконец, невозможно записать "\u0022" для строкового литерала, содержащего двойную кавычку (").
Строковый литерал — это ссылка на экземпляр класса String (§4.3.1, §4.3.3).
Более того, строковый литерал всегда ссылается на один и тот же экземпляр класса String. Это происходит потому, что строковые литералы — или, более общо, строки, которые являются значениями константных выражений (§15.28) — «интернациируются», чтобы использовать уникальные экземпляры, используя метод 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.28), вычисляются во время компиляции и затем обрабатываются так, как будто они являются литералами.
-
Строки, вычисленные путём конкатенации во время выполнения, создаются заново и, следовательно, различны.
-
Результат явного интернирования вычисленных строк — тот же объект
String, что и любой существующий строковый литерал с тем же содержимым.
Символьные и строковые последовательности экранирования позволяют представлять некоторые неграфические символы без использования Unicode-экранирования, а также символы одиночной кавычки, двойной кавычки и обратной косой черты в символьных литералах (§3.10.4) и строковых литералах (§3.10.5).
\ b (возврат на позицию BS, Unicode \u0008) \ t (горизонтальная табуляция HT, Unicode \u0009) \ n (перевод строки LF, Unicode \u000a) \ f (формат страницы FF, Unicode \u000c) \ r (возврат каретки CR, Unicode \u000d) \ " (двойная кавычка, Unicode ") \ ' (одинарная кавычка, Unicode ') \ \ (обратная косая черта, Unicode \) OctalEscape (восьмеричное значение, Unicode
\u0000 до \u00ff) 0 1 2 3 4 5 6 7 0 1 2 3 Производство OctalDigit выше взято из §3.10.1.
Ошибка компиляции, если символ, следующий за обратной косой чертой в последовательности экранирования, не является ASCII b, t, n, f, r, ", ', \, 0, 1, 2, 3, 4, 5, 6 или 7. Экранирование Unicode \u обрабатывается ранее (§3.3).
Восьмеричные экранирования представлены для совместимости с C, но могут выражать только значения Unicode от \u0000 до \u00FF, поэтому Unicode-экранирование обычно предпочтительнее.
Тип 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.