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

时间:2015-01-02 07:33:21

标签: java anonymous-class

我对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; }

DEMO

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

  

匿名类始终是内部类(第8.1.3节);它永远不会   静态

但是JLS, chapt 8

  

内部类是一个非显式或隐式的嵌套类   声明静态。

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

3 个答案:

答案 0 :(得分:7)

可以在静态上下文中创建一个类,而不是声明为静态,这就是这里发生的事情。让我们看一下被声明为静态的东西,并在静态上下文中创建意味着:

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

  

如果C是匿名类,则:

     
      
  • 如果类实例创建表达式出现在静态上下文中,那么我没有立即封闭的实例。

  •   
  • 否则,i的直接封闭实例就是这个。

  •   

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

  

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

     

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

通过说一个“隐含声明为静态”的嵌套类,它引用了接口中类的东西:

  

接口的成员类是隐式静态的(第9.5节),所以永远不会   被认为是内心阶级。

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

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

答案 1 :(得分:3)

您应该区分匿名和内部类

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

B b = new B(){ };

new B(){ }创建的类不能声明为静态。 (“匿名类总是内部类(第8.1.3节);它永远不是静态的”)。

静态嵌套类示例

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的嵌套类是所谓的static nested classes,而未声明为static的嵌套类是所谓的inner classes

答案 2 :(得分:1)

B是内部界面。因此,B是隐含的静态,您可以在静态上下文中引用B. (来自JLS 8.5.1:成员接口是隐式静态的(第9.1.1节)。

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

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
            }

        };

    }
}

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

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

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