是否每个内部类都需要一个封闭实例?

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

8.1.3。 内部类和封闭实例

[...]

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

[...]

其声明出现在静态上下文中的内部类的实例不包含词法封闭的实例。

也,

15.9.5。 匿名类声明

[...]

一个匿名类永远是一个内部类(§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() {}是一个没有封闭实例的嵌套类,在静态上下文中定义,但它不是静态嵌套类 - 它是一个内部类。

我们是否在日常使用中为这些术语指定了不恰当的含义?

作为一个相关的兴趣点,这个历史性的规范文件将顶层的术语定义为内层的对立面:

作为包成员的static类成员和类都称为顶级类。 它们与内部类不同之处在于顶级类只能直接使用它自己的实例变量。

而在通常的用法中,顶层被认为是嵌套的对立面。


从规范的角度来看,这个问题中的区别是非常有意义的:

  • 一个内部类应用了它的限制,这与封装实例的问题无关(例如,它可能没有静态成员);

  • 静态嵌套类的概念基本上是关于命名空间的; 这些类可以合理地称为顶层,以及我们通常认为是顶层类的东西。

  • 恰巧,从嵌套类声明中移除static会同时做两件事情:

  • 它使得类需要一个封闭的实例;
  • 它使课堂内在。
  • 我们很少考虑内在的作为限制; 我们只关注封闭的实例问题,这更加明显。 但是,从规范的角度来看,限制是一个至关重要的问题。

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


    那么,匿名类是不是也有一个封闭的实例呢? 它是静态的,而不是匿名类的实例。 考虑:

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

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

    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
    }
    

    其实他们之间根本没有区别。 我会说非静态的内部类只是一个语法糖 。 写一个普通的东西的一个简短的方法,没有更多。 唯一的区别在于,在非静态内部类中,在调用父构造函数之前分配了对封闭类的引用,这可能会影响某些逻辑,但我认为它并不那么重要,因此要分别考虑它们。

    PS有关相关主题的更多问题,这可能很有趣。

    链接地址: http://www.djcxy.com/p/16371.html

    上一篇: Is it true that every inner class requires an enclosing instance?

    下一篇: Difference between a HashMap and a dictionary ADT