是否可以使Java中的匿名内部类成为静态的?

2022-08-31 08:40:10

在Java中,嵌套类可以是其中之一,也可以不是。如果它们是 ,则它们不包含对包含实例的指针的引用(它们也不再称为内部类,它们称为嵌套类)。staticstatic

在不需要嵌套类引用时忘记创建该类可能会导致垃圾回收或转义分析出现问题。static

是否可以创建一个匿名的内部类?或者编译器会自动解决这个问题(它可以,因为不能有任何子类)?static

例如,如果我做一个匿名比较器,我几乎不需要引用外部:

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

答案 1

不,你不能,不,编译器无法弄清楚。这就是为什么FindBugs总是建议将匿名内部类更改为命名的嵌套类,如果它们不使用其隐式引用。staticthis

编辑:Tom Hawtin - tackline说,如果匿名类是在静态上下文中创建的(例如在方法中),则匿名类实际上是 .但JLS不同意mainstatic

匿名类永远不会 (§8.1.1.1)。匿名类始终是内部类 (§8.1.3);它永远不会(§8.1.1,§8.5.1)。匿名类始终是隐式的 (§8.1.1.2)。abstractstaticfinal

Roedy Green的Java词汇表说,在静态上下文中允许匿名类的事实是依赖于实现的:

如果你想让那些维护你的代码的人感到困惑,wags已经发现将允许在初始化代码和方法中包含匿名类,即使语言规范说比匿名类永远不会。当然,这些匿名类无权访问对象的实例字段。我不建议这样做。可以随时拉取该功能javac.exestaticstaticstatic

编辑 2:JLS 实际上在 §15.9.2 中更明确地涵盖了静态上下文:

C 是要实例化的类,让 i 成为正在创建的实例。如果 C 是一个内部类,那么 i 可能有一个立即封闭的实例。i (§8.1.3) 的紧闭实例按如下方式确定。

  • 如果 C 是一个匿名类,则:
    • 如果类实例创建表达式发生在静态上下文中 (§8.1.3),则 i 没有立即封闭的实例。
    • 否则,i 的紧闭实例是 。this

因此,静态上下文中的匿名类大致等同于嵌套类,因为它不保留对封闭类的引用,即使它在技术上不是类。staticstatic


答案 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版本中突然删除此功能。真诚地!