是否每个内部类都需要一个封闭实例?
术语内部类通常被认为是“需要封闭实例的嵌套类”。 但是,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();
}
}
然后在StaticInner
和Inner
类字节码中:
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?