Предупреждение Eclipse об синтетическом доступе для частных статических вложенных классов в Java?

Мой коллега предложил сделать несколько настроек форматирования и предупреждения Eclipse более строгими. Большинство этих изменений имеют смысл, но я получаю это одно странное предупреждение на Java. Вот несколько тестовых кодов для воспроизведения "проблемы":

package com.example.bugs;

public class WeirdInnerClassJavaWarning {
    private static class InnerClass
    {
        public void doSomething() {}
    }

    final private InnerClass anInstance;

    {
        this.anInstance = new InnerClass();   // !!!
        this.anInstance.doSomething();
    }
}
// using "this.anInstance" instead of "anInstance" prevents another warning,
// Unqualified access to the field WeirdInnerClassJavaWarning.anInstance    

Линия с!!! дает мне это предупреждение в Eclipse с моими новыми настройками:

Доступ к закрывающему конструктору WeirdInnerClassJavaWarning.InnerClass() эмулируется синтетическим аксессуаром метод. Увеличение его видимости улучшите свою производительность.

Что это значит? Предупреждение исчезает, когда я меняю "частный статический класс" на "защищенный статический класс", что не имеет для меня никакого смысла.


edit: Наконец-то я выяснил правильное исправление. Реальная проблема здесь заключается в том, что в этом вложенном частном статическом классе отсутствует публичный конструктор. Эта настройка удалила предупреждение:

package com.example.bugs;

public class WeirdInnerClassJavaWarning {
    private static class InnerClass
    {
        public void doSomething() {}
        public InnerClass() {}
    }

    final private InnerClass anInstance;

    {
        this.anInstance = new InnerClass();
        this.anInstance.doSomething();
    }
}

Я хочу, чтобы класс был частным вложенным классом (поэтому ни один другой класс не может иметь к нему доступ, включая подклассы окружающего класса), и я хочу, чтобы он был статическим классом.

Я до сих пор не понимаю, почему создание защищенного класса, а не частного, является еще одним методом исправления "проблемы", но, возможно, это причуда/ошибка Eclipse.

(извинения, я должен был бы назвать его NestedClass вместо InnerClass более понятным.)

Ответ 1

Вы можете избавиться от предупреждения следующим образом:

package com.example.bugs;

public class WeirdInnerClassJavaWarning {
    private static class InnerClass {
        protected InnerClass() {}  // This constructor makes the warning go away
        public void doSomething() {}
    }

    final private InnerClass anInstance;
    {
        this.anInstance = new InnerClass(); 
        this.anInstance.doSomething();
    }
}

Как говорили другие, Eclipse жалуется, потому что частный класс без явного конструктора не может быть создан извне, кроме как с помощью синтетического метода, который создает компилятор Java. Если вы возьмете свой код, скомпилируете его и затем декомпилируете с помощью jad (*), вы получите следующее (переформатированное):

public class Test {
  private static class InnerClass {
    public void doSomething() {}
    // DEFAULT CONSTRUCTOR GENERATED BY COMPILER:
    private InnerClass() {}

    // SYNTHETIC METHOD GENERATED BY THE JAVA COMPILER:    
    InnerClass(InnerClass innerclass) {
      this();
    }
  }

  public Test() {
    anInstance.doSomething();
  }

  // Your instance initialization as modified by the compiler:
  private final InnerClass anInstance = new InnerClass(null);
}

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

(*) Для jad, я связан со страницей в Википедии... домен, на котором размещена эта программа, истек, но ссылки Википедии на другой, который я сам не тестировал. Я знаю, что есть другие (возможно, более поздние) декомпиляторы, но это тот, который я начал использовать. Примечание. Он жалуется на декомпиляцию последних файлов классов Java, но он по-прежнему выполняет хорошую работу.

Ответ 2

Кстати, установка, чтобы выключить предупреждение, находится на странице Ошибок/Предупреждений Java в разделе "Стиль кода" и вызывается:

Доступ к недоступному элементу закрывающего типа

Ответ 3

Вы не можете создать экземпляр InnerClass из WeirdInnerClassJavaWarning. Он частный, JVM не позволит вам, но язык Java (по какой-то причине).

Следовательно, javac добавит дополнительный метод в InnerClass, который просто вернет новый InnerClass(), поэтому разрешит вам создавать экземпляры InnerClass из WeirdInnerClassJavaWarning.

Я не думаю, что вам действительно нужно избавиться от него, потому что падение производительности будет непрочно крошечным. Однако, если вы действительно этого хотите, вы можете.

Ответ 4

Я до сих пор не понимаю, почему включение вложенного класса, а не private, является еще одним методом исправления "проблемы", но, возможно, это причуда/ошибка Eclipse

Это не причуда/ошибка Eclipse, а просто функция Java. Спецификация языка Java, 8.8.9 говорит:

... если класс объявлен защищенным, то конструктор по умолчанию неявно получает защищенный модификатор доступа...

Ответ 5

Чтобы помочь людям, вот что вы получите, если вы используете исходный код класса в вопросе с помощью

javac -XD-printflat WeirdInnerClassJavaWarning.java -d tmp

Сырой вывод, компилятор добавил комментарии. Обратите внимание на добавление частного класса и конструктора синтетического пакета.

public class WeirdInnerClassJavaWarning {
    {
    }

    public WeirdInnerClassJavaWarning() {
        super();
    }
    {
    }
    private final WeirdInnerClassJavaWarning$InnerClass anInstance;
    {
        this.anInstance = new WeirdInnerClassJavaWarning$InnerClass(null);
        this.anInstance.doSomething();
    }
}

class WeirdInnerClassJavaWarning$InnerClass {

    /*synthetic*/ WeirdInnerClassJavaWarning$InnerClass(WeirdInnerClassJavaWarning$1 x0) {
        this();
    }

    private WeirdInnerClassJavaWarning$InnerClass() {
        super();
    }

    public void doSomething() {
    }
}

/*synthetic*/ class WeirdInnerClassJavaWarning$1 {
}

Ответ 6

Вы можете избавиться от него, используя область по умолчанию вместо частной или защищенной, т.е.

static class InnerClass ...

Также стоит отметить, что мой курсор на строке кода с предупреждением и нажатием ctrl-1, Eclipse может исправить это автоматически для вас.