Возможно ли сделать анонимные внутренние классы в 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.
Ответ 4
Внутренние классы не могут быть статическими - статический вложенный класс не является внутренним классом. В этом учебнике рассказывается об этом здесь.
Ответ 5
анонимные внутренние классы никогда не являются статическими (они не могут объявлять статические методы или не конечные статические поля), но если они определены в статическом контексте (статический метод или статическое поле), они ведут себя как статические в том смысле, что они не может получить доступ к нестатическим (т.е. экземпляру) членам охватывающего класса (как и все остальное из статического контекста)
Ответ 6
В примечании о создании анонимного внутреннего класса static, вызвав их в статическом методе.
Это фактически не удаляет ссылку. Вы можете протестировать это, пытаясь сериализовать анонимный класс, а не сделать класс, содержащий класс, сериализуемым.