126

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

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

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

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

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

6 回答 6

139

不,你不能,不,编译器无法弄清楚。static这就是为什么 FindBugs 总是建议在匿名内部类不使用隐式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 词汇表说,在静态上下文中允许匿名类的事实取决于实现:

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

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

C是被实例化的类,让i是被创建的实例。如果C是一个内部类,那么i可能有一个立即封闭的实例。i的直接封闭实例(第 8.1.3 节)确定如下。

  • 如果C是匿名类,则:
    • 如果类实例创建表达式出现在静态上下文中(第 8.1.3 节),则i没有立即封闭的实例。
    • 否则,i的直接封闭实例是this

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

于 2009-04-17T00:43:56.220 回答
16

我认为这里的命名法有点混乱,诚然这太愚蠢和混乱了。

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

我认为引用的作者将 static关键字与 static context混淆了。(诚​​然,JLS 在这方面也有点混乱。)

老实说,上面的所有模式都很好(无论你称它们为“嵌套”、“内部”、“匿名”等等……)。真的,没有人会在 Java 的下一个版本中突然删除这个功能。诚实地!

于 2009-04-17T15:13:32.543 回答
15

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

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

于 2009-04-17T10:18:59.553 回答
6

内部类不能是静态的——静态嵌套类不是内部类。Java 教程在这里讨论它

于 2009-04-17T00:43:15.660 回答
0

匿名内部类从不是静态的(它们不能声明静态方法或非最终静态字段),但如果它们是在静态上下文(静态方法或静态字段)中定义的,它们在某种意义上表现为静态,因为它们不能访问封闭类的非静态(即实例)成员(就像静态上下文中的所有其他内容一样)

于 2016-02-02T11:19:59.427 回答
-3

关于通过在静态方法中调用匿名内部类来使它们成为静态的注意事项。

这实际上并没有删除引用。您可以通过尝试序列化匿名类而不使封闭类可序列化来测试这一点。

于 2011-03-21T00:51:06.577 回答