Можно ли сделать анонимные внутренние классы в Java статические?


в 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 112

6 ответов:

нет, вы не можете, и нет, компилятор не может понять это. Вот почему FindBugs всегда предлагает изменить анонимные внутренние классы на named 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. Эти анонимные классы, конечно, не имеют доступа к полям экземпляра объекта. Я не рекомендую делать это. Элемент feature может быть вытащен в любое время.

Edit 2: JLS фактически охватывает статические контексты более явно в §15.9.2:

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

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

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

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

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

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

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

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

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

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

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

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

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