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

Why is an anonymous class in a static context valid

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

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

interface B{ int b = 1; }

DEMO

为什么代码可以编译? JLS, chapt 15 表示:

An anonymous class is always an inner class (§8.1.3); it is never static

但是 JLS, chapt 8

An inner class is a nested class that is not explicitly or implicitly declared static.

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

你应该区分匿名和内部 classes

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

B b = new B(){ };

new B(){ }创建的class不能声明为静态的。 ("An anonymous class is always an inner class (§8.1.3); it is never static").

静态嵌套 class 示例

class YourClass {
    static class StaticNestedClass {
    }
}

一个非静态嵌套 class 示例

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

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

B 是一个内部 接口 。因此 B 是隐式静态的,您可以在静态上下文中引用 B。 (来自 JLS 8.5.1:成员接口是隐式静态的(§9.1.1)。

但是通过 B 创建的匿名 class 不是静态的,如果从非静态上下文中引用,您可以访问外部对象:

public class Main{

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

            @Override
            public Ess3 getParent() {
                //return Ess3.this;  ERROR : non static variable cannot be referenced from static context
                return null;
            }
        };
        System.out.println(b.b);
    }

    interface B {

        int b = 1;
        Ess3 getParent();
    }

    /* a non static method */
    void foo() {
        B b = new B() {

            @Override
            public Ess3 getParent() {
                return Ess3.this; // this anonymous class is not static
            }

        };

    }
}

在您的示例中,您可能认为您创建了一个静态匿名内部 class,因为您创建了它 :

  • 来自静态嵌套界面
  • 在静态上下文中 - 因此无法访问外部对象

但非静态上下文中的相同声明证明静态嵌套接口创建非静态匿名 class

可以在静态上下文中创建一个 class 而无需声明为静态,这就是这里发生的情况。让我们看看声明为静态并在静态上下文中创建意味着什么:

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

If C is an anonymous class, then:

  • If the class instance creation expression occurs in a static context, then i has no immediately enclosing instance.

  • Otherwise, the immediately enclosing instance of i is this.

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

An inner class is a nested class that is not explicitly or implicitly declared static.

A nested class that is not an inner class may declare static members freely, in accordance with the usual rules of the Java programming language.

通过说嵌套的 class 即 'implicity declared static',它指的是接口中的 classes 之类的东西:

A member class of an interface is implicitly static (§9.5) so is never considered to be an inner class.

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

因为匿名classes没有声明为static,所以问题中的两个引号是一致的。