Ссылка на Public Enum приводит к анонимному классу

Во время компиляции я получаю анонимный класс, которого не ожидал. Соответствующий код следует, а затем более подробное объяснение:

Полнота CircuitType.java:

public enum CircuitType { V110A20, V110A30, V208A20, V208A30 }

Из Auditor.java, строки 3-9:

public class Auditor {
    private String[] fileNames;
    private int numV110A20;
    private int numV110A30;
    private int numV208A20;
    private int numV208A30;

Из Auditor.java, строки 104-121:

[...]
switch (newCircuit.getType()) {
    case V110A20:
        this.numV110A20++;
        break;
    case V110A30:
        this.numV110A30++;
        break;
    case V208A20:
        this.numV208A20++;
        break;
    case V208A30:
        this.numV208A30++;
        break;
    default:
        System.err.println("An Error Has Occured.");
        System.exit(-1);
        break;
}
[...]

Из Circuit.java, строки 1-5:

public class Circuit {
    private CircuitType myType;
    public CircuitType getType() {
        return this.myType;
    }
[...]

Когда команда

javac *.java

выполняется, генерируется анонимный класс Auditor $ 1.java. Очевидно, что все файлы располагаются рядом друг с другом в каталоге файловой системы, в котором больше ничего не содержится.

Когда строки 104–121 закомментированы, анонимный класс не создается.

Сначала я подумал, что это проблема с пакетом, поэтому поместил три класса в пакет, но я недостаточно знал о пакетах, чтобы заставить его работать. Если это действительно проблема с упаковкой, может ли кто-нибудь объяснить мне, как их пометить? Однако я бы предпочел не упаковывать их, если мне это не нужно.

Причина, по которой анонимный класс является проблемой, помимо того факта, что такие классы обычно означают проблему с пространством имен, заключается в том, что он нарушает мой Makefile, который я использую для автоматической компиляции.

Обновить


Прилагается консольный сеанс, который, я надеюсь, может пролить свет на эту загадку:

% javap 'Auditor$1'
Compiled from "Auditor.java"
class Auditor$1 extends java.lang.Object{
    static final int[] $SwitchMap$CircuitType;
    static {};
}

person Maarx    schedule 28.12.2009    source источник
comment
К сожалению, я не могу помочь с проблемой, но +1 опубликовал очень хорошо сформулированный вопрос.   -  person Topher Fangio    schedule 28.12.2009
comment
Вероятно, это не тот ответ, который вы хотели услышать, но make не совсем подходящий инструмент для разработки на Java. Я настоятельно рекомендую вместо этого использовать ant. По мере разработки более сложных приложений анонимные классы будут повсюду, и это правильно.   -  person Carl Smotricz    schedule 28.12.2009
comment
Мне было бы интересно увидеть больше Auditor.java. Основываясь на том, что вы здесь сказали, мне трудно поверить, что проблема в Circuit.java.   -  person Shaun    schedule 28.12.2009
comment
По вашему запросу я добавил еще Auditor.java.   -  person Maarx    schedule 28.12.2009
comment
StackOverflow, вероятно, не взорвется, если вы разместите свой полный код. С другой стороны, вы можете прислать мне свой код по электронной почте. [email protected].   -  person Carl Smotricz    schedule 28.12.2009
comment
@Carl: Я хотел бы, однако, это собственность компании (хотя я единственный автор). Я толкнул конверт так далеко, как только посмел.   -  person Maarx    schedule 28.12.2009
comment
Обновил свой ответ и добавил новый комментарий.   -  person Carl Smotricz    schedule 28.12.2009
comment
возможный дубликат stackoverflow.com/questions/1834632 /   -  person Brad Cupit    schedule 09.02.2012


Ответы (2)


Я пошел дальше и создал небольшой проект, содержащий опубликованный вами исходный код и достаточно фреймворка для его компиляции. У меня есть 3 файла классов: Circuit.class, CircuitType.class и Auditor.class - как и ожидалось.

Все это под Java 1.6. Но, как указывали другие, я думаю, что ваш диагноз проблемы неверен.

Анонимные классы легко случайно сгенерировать: обычно такая конструкция, как

Circuit myCircuit = new Circuit() {
   public CircuitType getCircuitType() {
      return XXX;
   }
}

создаст его, например. Если у вас будет больше кода, хорошие специалисты из SO могут точно определить вашу ошибку.

Было бы интересно и поучительно дизассемблировать ваши файлы классов с помощью javap или, что еще лучше, "настоящего" дизассемблера Java, такого как JD.


Обновить

Добавил ваш новый код Auditor в мой ... без изменений. Никаких анонимных занятий.

Ваш код, конечно, правильный (насколько мы его видим), но дизайн не очень объектно-ориентированный. Некоторые люди указали бы, что вам придется расширять декларации счетчика и оператор switch каждый раз, когда появляется новый тип схемы.

Вы также не особо используете «специальные возможности» перечислений. У меня есть сильно упрощенная версия вашего Auditor метода:

   private int[] counters = new int[CircuitType.values().length];

   public void tallySomething() {
      Circuit newCircuit = new Circuit();
      counters[newCircuit.getType().ordinal()]++;
  }

Обновление 2

Я нашел ваш javap вывод весьма показательным. См. Мой комментарий ниже.

Мои выводы:

  1. Да, очевидно, ваш Java impl использует для переключателя анонимный класс. Хромой, но законной.
  2. You have the following options:
    • eliminate the switch
    • использовать другую реализацию Java
    • жить с анонимным классом; бросьте make и используйте ant, чтобы охватить анонимные классы и другие странности Java.

Поскольку у вас проблемы только из-за нестандартной настройки компиляции, я бы выбрал последнее решение и решил проблему там.

person Carl Smotricz    schedule 28.12.2009
comment
Я включил дополнительный код из Auditor.java по вашему запросу. Блок кода строки 104-121 наверняка является виновником, поскольку анонимный класс не создается, когда этот блок кода закомментирован. Я считаю, что включил все, что имеет отношение к этому блоку кода. Если вам еще что-нибудь понадобится, дайте мне знать. - person Maarx; 28.12.2009
comment
Мой мозг взорвался. Дважды. Для меня определенно существует анонимный класс с оператором switch, и определенно нет анонимного класса, когда оператор switch закомментирован. Когда вы сказали, что у вас все еще нет анонимного класса, я переместил код из своей среды разработки UNIX на одноразовую виртуальную машину Windows с последним обновлением JDK и перекомпилировал. Я по-прежнему получаю анонимный класс с оператором switch и без него. - person Maarx; 28.12.2009
comment
Ваш метод подсчета также стал неожиданностью. Я переписываю свой переключатель с вашим методом, потому что он лучше, и чтобы посмотреть, может ли он решит проблему анонимного класса. - person Maarx; 28.12.2009
comment
@Carl: Я обновил свой вопрос, добавив 'javap'. Хотя я никогда раньше не использовал 'javap' и даже не знал об этом, пока вы не упомянули об этом, результат, похоже, однозначно связан с характером оператора switch. Однако я больше ничего не могу предугадать. Возможно, ты сможешь? - person Maarx; 28.12.2009
comment
Да ... javap действительно интересен. Очевидно, ваша конкретная реализация Java использует этот анонимный класс для реализации функции включения-перечисления. Следует понимать, что оператор java switch действительно «делает» только ints. Большинство этих интересных новых языковых функций - всего лишь синтаксический сахар базовой Java. Кажется, оператор switch реализуется путем поиска перечисления на карте и последующего включения int, сохраненного в качестве значения. - person Carl Smotricz; 28.12.2009
comment
Из любопытства, какую java-реализацию вы используете, НЕ создавая анонимный класс для коммутатора? Я бы подумал, что установка самой последней версии JDK прямо с веб-сайта Sun на предварительно созданный HP Compaq Core2 vPro под управлением Windows Vista - это примерно такая же стандартная реализация, какую вы могли бы получить, и у меня все еще есть анонимный класс. - person Maarx; 30.12.2009
comment
Большую часть работы с Java я выполняю с помощью Eclipse IDE. Некоторые другие люди упоминали, что этой проблемы не возникает с Eclipse. Насколько мне известно, в Eclipse встроен компилятор IBM, который выполняет инкрементную компиляцию. Я думаю, это как бы обходит установленный компилятор. Компилятор очень хорош; в данном конкретном случае видимо лучше стандартного :) - person Carl Smotricz; 30.12.2009

Похоже, что (по крайней мере, в некоторых случаях) для оператора switch будет сгенерирован внутренний класс:

перечисление Java и дополнительные файлы классов

person Community    schedule 28.12.2009