Можно ли сделать анонимные внутренние классы в Java статическими? - PullRequest
116 голосов
/ 17 апреля 2009

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

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

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

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

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

Ответы [ 6 ]

133 голосов
/ 17 апреля 2009

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

Edit: 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).

Java Глоссарий Роди Грина говорит, что факт, что анонимные классы разрешены в статическом контексте, зависит от реализации:

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

Редактировать 2: JLS на самом деле более явно охватывает статические контексты в §15.9.2 :

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

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

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

15 голосов
/ 17 апреля 2009

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

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

14 голосов
/ 17 апреля 2009

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

Как бы вы их ни называли, эти шаблоны (и несколько вариантов с различной видимостью) все возможные, нормальные, легальные 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 разрешит анонимный доступ классы внутри статического кода инициализации и статические методы, хотя спецификация языка говорит чем аноним классы никогда не бывают статичными

Я думаю, что цитируемый автор путает статическое ключевое слово 1019 * со статическим context . (Следует признать, что JLS также немного запутан в этом отношении.)

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

6 голосов
/ 17 апреля 2009

Внутренние классы не могут быть статичными - статический вложенный класс не является внутренним классом. Об этом рассказывается в руководстве по Java .

0 голосов
/ 02 февраля 2016

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

0 голосов
/ 21 марта 2011

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

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

...