Имя класса Java, содержащее знак доллара, не компилируется, если присутствует внутренний класс

У меня определены следующие классы Java:

mac-grek:javajunk grek$ cat A\$B.java
class A$B {}
mac-grek:javajunk grek$ cat A.java
public class A {
  public static class B {}
}
mac-grek:javajunk grek$ cat Main.java 
public class Main {

  public static void main(String[] args) {
    System.out.println(A.B.class.getName());
    System.out.println(A$B.class.getName());
  }

}

Когда я пытаюсь скомпилировать их, я получаю следующие ошибки:

mac-grek:javajunk grek$ javac 'A$B.java' A.java Main.java
A.java:2: duplicate class: A.B
  public static class B {}
                ^
Main.java:4: cannot find symbol
symbol  : class B
location: class A
    System.out.println(A.B.class.getName());
                        ^
Main.java:5: cannot find symbol
symbol  : class A$B
location: class Main
    System.out.println(A$B.class.getName());
                       ^
3 errors

Если я удалю A.java файл и System.out.println(A.B.class.getName()); от Main.java все компилируется:

mac-grek:javajunk grek$ cat A\$B.java 
class A$B {}
mac-grek:javajunk grek$ cat Main.java 
public class Main {

  public static void main(String[] args) {
    System.out.println(A$B.class.getName());
  }

}
mac-grek:javajunk grek$ javac A\$B.java Main.java
mac-grek:javajunk grek$ 

Так что Java позволяет мне определить класс, содержащий знак доллара в его имени. Как я могу скомпилировать мой оригинальный пример?

3 ответа

Решение

У вас конфликт имен, потому что вы определили класс верхнего уровня A$B, имеющий то же имя, что и сгенерированное имя для статического внутреннего класса B класса A. Поскольку у вас есть оба, компилятор не может разрешить конфликт.

JLS говорит:

Символ $ следует использовать только в механически сгенерированном исходном коде или редко для доступа к уже существующим именам в устаревших системах.

Поскольку вы решили не соблюдать это правило, вас укусил Джавак. Я бы просто переименовал A$B во что-то другое.

Это правило очень расплывчато.

Я не согласен. Для меня это говорит "не делай этого... если ты не знаешь, что делаешь". Это не говорит почему, но это не нужно. В самом деле, это не может полностью объяснить, почему, потому что некоторые из '$' в идентификаторы могут входить сторонние программы.

Почему javac будет беспокоиться, если мой код исходит от какого-то генератора или написан вручную?

Это не "все равно". Но с другой стороны, предполагается, что вы знаете, что делаете, если решите игнорировать рекомендации JLS.

Дело в том, что люди, которые пишут генераторы, должны знать, что имена двоичных классов для внутренних классов представлены с использованием '$' персонаж. Другие люди должны просто следовать советам в JLS.

Причина, по которой в спецификации языка Java не указано, как JVM использует '$' это "разделение интересов". С точки зрения JLS, это просто деталь реализации. Действительно, возможно, что кто-то реализует язык Java для платформы виртуальной машины, которая по-разному обрабатывает внутренние классы.


Я хотел бы точно знать, в каких случаях я могу использовать $ в названиях моих классов.

На это невозможно ответить однозначно. И, наверное, хорошо, что это невозможно; увидеть ниже.

JLS должен быть очень точным и формальным и не должен ссылаться на психическое состояние читателя при интерпретации его утверждений.

  1. Есть некоторые области, где было бы плохо для JLS быть формальным и точным. Это одна из них. Например, если бы они объявили, что "$" может безопасно, если вы следуете правилам X, Y и Z, это ограничит их возможное использование "$" в будущих версиях Java. Изменение правил о том, какие идентификаторы работоспособны, может вызвать серьезные проблемы с совместимостью исходного кода.

    (Другими областями применения этого принципа являются Модель памяти и семантика сбора мусора.)

  2. JLS не относится к вашему психическому состоянию. Это были мои слова.

Как ваш класс class A$B и ваш static class B разделяет то же самое. Компилятор генерирует OuterClassName$InnerClassName как имя класса для вложенных классов

Другие вопросы по тегам