Ограничения на имена зафиксированы в спецификации JVM:
Имена классов и интерфейсов, которые появляются в структурах файлов классов, всегда представлены в полностью определенной форме, известной как двоичные имена (JLS §13.1). Такие имена всегда представлены в виде структур CONSTANT_Utf8_info
(§4.4.7) и, таким образом, могут быть получены, если нет дополнительных ограничений, из всего кодового пространства Unicode…
По историческим причинам синтаксис двоичных имен, которые появляются в структурах файлов классов, отличается от синтаксиса двоичных имен, описанных в JLS §13.1. В этой внутренней форме точки ASCII (.
), которые обычно разделяют идентификаторы, составляющие двоичное имя, заменяются косой чертой ASCII (/
). Сами идентификаторы должны быть неквалифицированными именами (§4.2.2).
Имена методов, полей, локальных переменных и формальных параметров хранятся как неполные имена. Неполное имя должно содержать по крайней мере одну кодовую точку Unicode и не должно содержать никаких символов ASCII .
;
[
/
(то есть точки, точки с запятой, левой квадратной скобки или косой черты).
Имена методов имеют дополнительные ограничения, поэтому, за исключением имен специальных методов <init>
и <clinit>
(§2.9), они не должны содержать символы ASCII <
или >
(то есть левая угловая скобка или правая угловая скобка).
Итак, ответ таков: есть лишь несколько символов, которые нельзя использовать на двоичном уровне. Во-первых, /
— это разделитель пакетов. Затем нельзя использовать ;
и [
, поскольку они имеют особое значение в подписи полей и метод подписи, которые могут содержать имена типов. В этих подписях [
начинает тип массива, а ;
отмечает конец имени ссылочного типа.
Нет четкой причины, по которой .
запрещен. Он не используется в JVM и имеет значение только в пределах общие подписи, но если вы используете общие подписи, имена типов дополнительно ограничиваются тем, что им не разрешено содержать <
, >
, :
, а также эти символы имеют особое значение внутри общие подписи тоже.
Следовательно, нарушение спецификации путем использования .
в идентификаторах не влияет на основную функцию JVM. Обфускаторы это делают. Полученный код работает, но вы можете столкнуться с проблемами с Reflection при запросе подписей универсального типа. Кроме того, преобразование двоичных имен в исходное имя путем замены всех /
s на .
s станет необратимым, если двоичное имя содержит .
s.
Интересно, что было предложение поддерживать все возможные идентификаторы в синтаксисе Java (см. пункт 3, «экзотические идентификаторы»), но в финальную версию Java 7 он не попал. И, похоже, сейчас никто не предпринимает новых попыток его внедрить.
Существует дополнительное техническое ограничение: имена не могут иметь Измененное представление UTF-8 длиннее 65 535 байт, поскольку число байтов хранится как беззнаковое короткое значение.
person
Holger
schedule
28.05.2015
do
,while
и т. д., чтобы затруднить декомпиляцию кода. (Его все еще можно декомпилировать, но полученный код в основном бесполезен) - person Marco13   schedule 28.05.2015