Предупреждение 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 может исправить это автоматически для вас.