每个内部类都需要一个封闭的实例吗?

时间:2013-12-09 10:58:03

标签: java class jls

术语内部类通常用于表示“需要封闭实例的嵌套类”。但是,JLS声明如下:

  

8.1.3. Inner Classes and Enclosing Instances

     

[...]

     

内部类包括本地(§14.3),匿名(§15.9.5)和非静态成员类(§8.5)。

     

[...]

     

内部类的实例,其声明发生在静态上下文中,没有词法封闭的实例。

此外,

  

15.9.5. Anonymous Class Declarations

     

[...]

     

匿名类始终是内部类(第8.1.3节);它永远不会static(§8.1.1,§8.5.1)。

众所周知,匿名类可以在静态上下文中声明:

class A {
  int t() { return 1; }
  static A a =  new A() { int t() { return 2; } };
}

要描述它,

new A() {}是一个没有封闭实例的嵌套类,在静态上下文中定义,但它不是静态嵌套类 - 它是一个内部类。

我们是否都在日常使用中为这些条款赋予了不恰当的含义?

作为一个相关的兴趣点,this historical specification document将术语顶级定义为 inner 的对立面:

  

static类成员和类的类   包成员都被称为顶级类。他们与内心不同   类中的顶级类只能直接使用自己的实例   变量

在常见用法中,顶级嵌套相反。

3 个答案:

答案 0 :(得分:5)

从规范的角度来看,问题中提出的区别是完全合理的:

  • 内部类有一些限制,它与封闭实例的问题无关(例如,它可能没有静态成员);

  • 静态嵌套类的概念基本上只是关于命名空间;这些类可能被称为顶级,以及我们通常认为是顶级类的。

恰好从嵌套类声明中删除static会同时执行两个单独的操作:

  1. 它使类需要一个封闭的实例;
  2. 它使类内部
  3. 我们很少将内部视为必要的限制;我们只专注于封闭实例关注点,这更加明显。但是,从规范的角度来看,限制是一个至关重要的问题。

    我们缺少的是一个需要封闭实例的类的术语。 JLS没有定义这样的术语,所以我们(不知道,似乎)劫持了一个相关但实际上本质上不同的术语来表示。

答案 1 :(得分:0)

那么,匿名类在你的情况下是否也有一个封闭的实例?它是静态的引用,而不是匿名类的实例。考虑:

class A {
   int t() { return 1; }
   static A a = new A() { { System.out.println(t()); } };
}

答案 2 :(得分:-1)

静态内部类和无静态之间没有区别。我不明白为什么他们应该分开考虑。看看下面的代码:

public class Outer {
    public static class StaticInner{
        final Outer parent;

        public StaticInner(Outer parent) {
            this.parent = parent;
        }
    };
    public class Inner{}

    public static void main(String[] args) {
        new StaticInner(new Outer());
        new Outer().new Inner();
    }
}

然后在StaticInnerInner类字节码:

public class so.Outer$Inner extends java.lang.Object{
final so.Outer this$0;
public so.Outer$Inner(so.Outer);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield        #1; //Field this$0:Lso/Outer;
   5:   aload_0
   6:   invokespecial   #2; //Method java/lang/Object."<init>":()V
   9:   return

}

public class so.Outer$StaticInner extends java.lang.Object{
final so.Outer parent;
public so.Outer$StaticInner(so.Outer);
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   aload_1
   6:   putfield        #2; //Field parent:Lso/Outer;
   9:   return
}

实际上它们之间没有任何区别。我会说非静态内部类只是一个语法糖。写一个共同的东西的更短的方式,没有更多。唯一的细微差别是,在非静态内部类中,在调用父构造函数之前分配对封闭类的引用,这可能会影响某些逻辑,但我不认为它是如此重要,需要单独考虑它们。

P.S。 One more question on a related topic, which might be interesting.