Почему некоторые символы ASCII не могут быть выражены в виде 'uXXXX' в исходном коде Java?


Я споткнулся об это (снова) сегодня:

class Test {
    char ok = 'n';
    char okAsWell = 'u000B';
    char error = 'u000A';
}

Он не компилируется:

недопустимая символьная константа в строке 4.

компилятор, кажется, настаивает, чтобы я написал 'n' вместо этого. Я не вижу причин для этого, но это очень раздражает.

есть ли логическое объяснение, почему символы, которые имеют специальное обозначение (например,t,n,r)должны выражаться в этой форме на Java источник?

5 57

5 ответов:

символы Юникода заменяются их значением, поэтому ваша строка заменяется компилятором на:

char error = '
';

который не является допустимым оператором Java.

это продиктовано Спецификация Языка:

компилятор для языка программирования Java ("компилятор Java") сначала распознает Unicode escapes на своем входе, переводя символы ASCII ,за которыми следуют четыре шестнадцатеричные цифры, в кодовую единицу UTF-16 (§3.1) указывается шестнадцатеричное значение, а все остальные символы передаются без изменений. Представление дополнительных символов требует двух последовательных экранирований Юникода. Этот шаг перевода приводит к последовательности входных символов Юникода.

Это может привести к удивительным вещам, например, это действительная программа Java (она содержит скрытые символы юникода) -предоставлен Питер Lawrey:

public static void main(String[] args) {
    for (char c‮h = 0; c‮h < Character.MAX_VALUE; c‮h++) {
        if (Character.isJavaIdentifierPart(c‮h) && !Character.isJavaIdentifierStart(c‮h)) {
            System.out.printf("%04x <%s>%n", (int) c‮h, "" + c‮h);
        }
    }
}

Unicode escape-последовательности, такие как \u000a заменены по фактическим символам, которые они представляют, прежде чем компилятор Java сделает что-либо еще с исходным кодом. И так, ваша программа в конечном итоге заканчивается на

char ch = '
';

так \u000a в исходном коде заменяется внутренне символом перевода строки. Заметим, что это происходит до того, как компилятор читает и интерпретирует исходный код.

со ссылкой на Язык Java Спецификация:

это-ошибка времени компиляции для признак конца строки (§3.4) появляться после открытия ' и перед закрытием '.

и как хорошо все знать наизусть, \n это признак конца строки, цитирую:

 LineTerminator:
    the ASCII LF character, also known as "newline"
    the ASCII CR character, also known as "return"
    the ASCII CR character followed by the ASCII LF character

другие символы, которые могут вызвать проблемы \,' и " например.

Я думаю, что причина в том, что \uXXXX последовательности расширяются при анализе кода, см. JLS §3.2. Лексические Переводы.

это описано в разделе 3.3. Unicode Escapes http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html. Javac сначала находит последовательности \uxxxx .java и заменяет их реальными символами, а затем компилирует. В случае

char error = '\u000A';

\u000A будет заменить на newline код символа (10) и фактический текст будет

char error = '
';

потому что компилятор обрабатывает их так же, как незакодированным текстом.

это допустимый код:

 class \u00C9 {}