Возможно ли сделать анонимные внутренние классы в Java static?

В Java вложенные классы могут быть либо static, либо нет. Если они static, они не содержат ссылки на указатель содержащего экземпляра (они также больше не называются внутренними классами, они называются вложенными классами).

Забывая сделать вложенный класс static, когда он не нуждается в этой ссылке, может привести к проблемам с сбором мусора или анализом утечки.

Возможно ли сделать анонимный внутренний класс static? Или компилятор автоматически определяет это (что могло бы быть, потому что не может быть никаких подклассов)?

Например, если я делаю анонимный компаратор, мне почти никогда не нужна ссылка на внешнюю сторону:

  Collections.sort(list, new Comparator<String>(){
       int compare(String a, String b){
          return a.toUpperCase().compareTo(b.toUpperCase());
       }
  }

Ответ 1

Нет, вы не можете, и нет, компилятор не может понять это. Вот почему FindBugs всегда предлагает изменить анонимные внутренние классы на названные static вложенные классы, если они не используют свою неявную ссылку this.

Изменить: Tom Hawtin - tackline говорит, что если анонимный класс создается в статическом контексте (например, в методе main), анонимный класс на самом деле static. Но JLS не согласен:

Анонимный класс никогда не abstract (§8.1.1.1). Анонимный класс всегда является внутренним классом (§8.1.3); это никогда не static (§8.1.1, §8.5.1). Анонимный класс всегда неявно final (§8.1.1.2).

Roedy Green Java Glossary говорит, что факт, что анонимные классы разрешены в статическом контексте, зависит от реализации:

Если вы хотите дезориентировать тех, кто поддерживает ваш код, wags обнаружили, что javac.exe разрешает анонимные классы внутри static init code и static методы, хотя спецификация языка говорит, что анонимные классы никогда не static. Эти анонимные классы, конечно, не имеют доступа к полям экземпляра объекта. Я не рекомендую это делать. Функция может быть вытащена в любое время.

Изменить 2: JLS фактически более подробно описывает статические контексты в §15.9.2:

Пусть C - экземпляр класса, и пусть я - создаваемый экземпляр. Если C является внутренним классом, тогда я могу иметь экземпляр с непосредственным включением. Прилагаемый экземпляр я (§8.1.3) определяется следующим образом.

  • Если C - анонимный класс, то:
    • Если выражение создания экземпляра класса встречается в статическом контексте (§8.1.3), то у меня нет немедленно оговариваемого экземпляра.
    • В противном случае непосредственным экземпляром я является this.

Таким образом, анонимный класс в статическом контексте примерно эквивалентен вложенному классу static тем, что он не сохраняет ссылку на охватывающий класс, хотя это технически не класс static.

Ответ 2

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

Как бы вы их ни называли, эти шаблоны (и несколько вариантов с различной видимостью) все возможные, нормальные, юридические Java:

public class MyClass {
  class MyClassInside {
  }
}

public class MyClass {
  public static class MyClassInside {
  }
}

public class MyClass {
  public void method() {
    JComponent jc = new JComponent() {
      ...
    }
  }
}

public class MyClass {
  public static void myStaticMethod() {
    JComponent jc = new JComponent() {
      ...
    }
  }
}

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

Но эта цитата просто неверна:

javac.exe позволит анонимно классы внутри статического кода инициализации и статические методы, хотя язык говорит, чем анонимный классы никогда не статичны

Я думаю, что цитируемый автор путает статическое ключевое слово со статическим контекстом. (По общему признанию, JLS также немного запутан в этом отношении.)

Честно говоря, все вышеприведенные шаблоны хороши (что бы вы ни называли их "вложенными", "внутренними", "анонимными" независимо от того...). Действительно, никто не собирается внезапно удалить эту функциональность в следующей версии Java. Честно!

Ответ 3

Вид. Анонимный внутренний класс, созданный в статическом методе, будет, очевидно, эффективно статичным, потому что нет внешнего источника для этого.

Существуют некоторые технические различия между внутренними классами в статических контекстах и ​​статическими вложенными классами. Если вам интересно, прочитайте JLS 3rd Ed.

Ответ 5

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

Ответ 6

В примечании о создании анонимного внутреннего класса static, вызвав их в статическом методе.

Это фактически не удаляет ссылку. Вы можете протестировать это, пытаясь сериализовать анонимный класс, а не сделать класс, содержащий класс, сериализуемым.