为什么静态上下文中的匿名类有效

2022-09-04 21:53:58

我对Java中的匿名类有什么误解。请考虑以下简单示例:

public static void main (String[] args) throws java.lang.Exception
{
    B b = new B(){ };
    System.out.println(b.b);
}

interface B{ int b = 1; }

演示

为什么代码会编译?JLS,第15章说:

匿名类始终是内部类 (§8.1.3);它从来都不是静态的

但是JLS,第8章

内部类是未显式或隐式声明为静态的嵌套类。

所以匿名类是一个内部类。但我们在静态上下文中使用它们。为什么这里是正确的?


答案 1

可以在静态上下文中创建类,而无需将其声明为静态,这就是这里发生的情况。让我们看一下在静态上下文中声明为静态并在静态上下文中创建的含义:

在静态上下文中创建的匿名类与非静态上下文之间的区别在于它是否具有封闭实例:

如果 C 是一个匿名类,则:

  • 如果类实例创建表达式发生在静态上下文中,则 i 没有立即封闭的实例。

  • 否则,i 的紧闭实例是 this。

声明为静态的嵌套类允许静态成员:

内部类是未显式或隐式声明为静态的嵌套类。

不是内部类的嵌套类可以根据 Java 编程语言的通常规则自由声明静态成员。

通过说一个“隐式声明的静态”的嵌套类,它指的是接口中的类之类的东西:

接口的成员类是隐式静态的 (§9.5),因此从不将其视为内部类。

匿名类不声明为静态(既不使用关键字显式声明,也不隐式声明(如在接口内部),因此不允许声明静态成员。但是,它们可以在静态上下文中创建,这意味着它们不引用封闭的实例。

由于匿名类未声明为静态,因此问题中的两个引号都是一致的。


答案 2

您应该区分匿名类和内部类

使用此语句,您可以创建一个实现接口 B 的类。该类没有名称,因此称为匿名类。编译将创建一个具有以下命名规则 YourClass$1.class的类文件(其中 1 是一个序号,基于 YourClass 中匿名类的数量。javac

B b = new B(){ };

创建的类不能声明为静态。(“匿名类始终是内部类 (§8.1.3);它从来都不是静态的”)。new B(){ }

静态嵌套类示例

class YourClass {
    static class StaticNestedClass {
    }
}

非静态嵌套类示例

class YourClass {
    // An inner class is a nested class that is not explicitly or implicitly declared static.
    class InnerClass {
    }
}

有两种类型的嵌套类:静态和非静态。被声明为静态的嵌套类是所谓的,而未声明为静态的嵌套类是所谓的。static nested classesinner classes


推荐