Eclipse предупреждение о синтетическом аксессоре для частных статических вложенных классов в Java? - PullRequest
46 голосов
/ 28 мая 2009

Мой коллега предложил сделать несколько настроек форматирования кода и предупреждений в 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, чтобы быть более понятным.)

Ответы [ 6 ]

43 голосов
/ 28 мая 2009

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

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, но все равно хорошо работает.

20 голосов
/ 30 августа 2011

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

Доступ к недоступному элементу вложенного типа

9 голосов
/ 28 мая 2009

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

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

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

3 голосов
/ 28 мая 2009

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

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

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

2 голосов
/ 21 августа 2013

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

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 {
}
0 голосов
/ 28 мая 2009

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

static class InnerClass ...

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

...