是否可以在Java静态中创建匿名内部类?

问题

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

忘记在不需要该引用的情况下创建嵌套类static会导致垃圾收集或转义分析出现问题。

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

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

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

#1 热门回答(129 赞)

不,你不能,也不,编译器无法搞清楚。这就是为什么FindBugs总是建议将匿名内部类更改为namedstaticnested类,如果他们不使用他们的implicitthis引用。

**编辑:**Tom Hawtin - tackline说如果匿名类是在静态上下文中创建的(例如在main方法中),那么匿名类实际上是static。但是JLSdisagrees

匿名类永远不是抽象的(§8.1.1.1)。匿名类始终是内部类(第8.1.3节);它永远不会是静态的(§8.1.1,§8.5.1)。匿名类总是隐式最终的(第8.1.1.2节)。

Roedy Green的Java Glossarysays that在静态上下文中允许匿名类的事实依赖于实现:

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

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

让C成为实例化的类,让我成为正在创建的实例。如果C是内部类,那么我可能有一个立即封闭的实例。 i(§8.1.3)的直接封闭实例确定如下。如果C是一个匿名类,那么:如果类实例创建表达式出现在静态上下文中(第8.1.3节),那么我没有立即封闭的实例。否则,i的直接封闭实例就是这个。

因此,静态上下文中的匿名类大致相当于astaticnested类,因为它不保留对封闭类的引用,即使它在技术上不是astaticclass。


#2 热门回答(14 赞)

我认为这里的术语存在一些混淆,这无疑是太愚蠢和混乱。

无论你怎么称呼它们,这些模式(以及一些具有不同可见性的变化)都是所有可能的,正常的,合法的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将允许静态init代码和静态方法中的匿名类,即使语言规范说明匿名类永远不是静态的

我认为引用的作者将statickeyword与staticcontext混淆。 (不可否认,JLS在这方面也有点令人困惑。)

老实说,上面的所有模式都很好(无论你称之为"嵌套","内部","匿名"等等......)。实际上,在下一版Java中,没有人会突然删除此功能。说实话!


#3 热门回答(13 赞)

有点。在静态方法中创建的匿名内部类显然是有效的静态,因为外部没有外部源。

静态上下文和静态嵌套类中的内部类之间存在一些技术差异。如果你有兴趣,请阅读JLS 3rd Ed。