温故知新:nested class & inner class
温故而知新,可以为师矣。
— 孔子 《论语》
如果不是去读 Android 的源码,我不会想到在自己的 toolkit 里还有 inner class 这么一把小“锉刀”。如果不是发现non-static variable this cannot be referenced from a static context
,我不会想到去查 inner class 的知识,也就不会发现自己对 inner class 的理解一直都是错误的。
七年前学习 Java 时,明白一个 class 可以定义在另外一个 class 里,编译后各自生一个后缀为 .class 的文件,此后很少用到这种方式,直到看到 Android ,叹其大量运用 inner class。当我试图对某个 inner class 进行修改,删去其类修饰符(class modifier)中的 static 时,Eclipse 给出了这样的提示:
No enclosing instance of type Hello is accessible. Must qualify the allocation with an enclosing instance of type Hello (e.g. x.new A() where x is an instance of Hello).
顿时我糊涂了,明明看到诸如 EnclosingClass.InnerClass inner = new Enclosing.InnerClass() 一类的写法大行其道,怎么我写出来就出错了呢?当我按照提示,首先获得 EnclosingClass 的实例 outter,然后再EnclosingClass.InnerClass inner = outter.new InnerClass(),编译器告诉我:OK!
在代码编译通过并正常执行后,我对自己的 Java 知识产生了怀疑:我对 inner class 的理解是充分和正确的吗?在质疑中,我找到《The Java Language Specification》对 inner class 的定义:
An inner class is a nested class that is not explicitly or implicitly declared static.
虽然有了上述定义,可还是不清楚,其采用了一个新的名词 nested class 来解释,可是 nested class 又是什么呢?继续来看《The Java Language Specification》:
A nested class is any class whose declaration occurs within the body of another class or interface. A top level class is a class that is not a nested class.
一个 class A 如果定义在了另一个 class B 或 interface B 里,那么这个 class A 就是 nested class,class B 或 interface B 则被称为 enclosing class。至于 class A 是定义在了 class B 或 interface B 的什么地方,例如 method 和 constructor,则是没有限制的。再打开《The Java Tutorial》,找到 nested class 的相关表述:
Nested classes are divided into two categories: static and non-static. Nested classes that are declared static are simply called static nested classes. Non-static nested classes are called inner classes.
恍然大悟,原来我理解中的 inner class 其实是 nested class,只有non-static 的 nested class 才能被称为 inner class,否则就是 static nested class!《The Java Tutorial》把 nested class 笼统分为两类,而更深入一点的话,inner class 还可以继续划分成三类:local class、anonymous class、non-static member class。根据《The Java Language Specification》的描述,local class 和 member class 分别定义如下:
A local class is a nested class that is not a member of any class and that has a name.
A member class is a class whose declaration is directly enclosed in another class or interface declaration.
由此看来,简单把 inner class 等同于 non-static member class 也是不正确。焦点重新回到 inner class 上,了解一下 inner class 的部分规则:
Inner classes may not declare static initializers (§8.7) or member interfaces. Inner classes may not declare static members, unless they are compile-time constant fields (§15.28).
It is a compile-time error if a local class declaration contains any one of the following access modifiers: public, protected, private, or static.
An anonymous class is never abstract (§8.1.1.1). … An anonymous class is always implicitly final (§8.1.1.2).
inner class 不能被声明为 static,不能有 static initalizer(静态初始化块),不能是 interface(因为 member interface 一律都是 static 的),不能声明 static member,–compile-time constant field (诸如 static final int i = 0)除外。an inner class is associated with an instance of its enclosing class
,换句话说,没有 enclosing class 的 instance 就不会有 inner class 的 instance,我想 enclosing class 和 inner class 之间可以用 UML 中的 composition 来表示。
尽管语言设计者给 inner class 了这么多的限制,但是也不忘给它一些弥补,–inner class 可以访问 enclosing class 的所有 member,包括 method、field、nested class、nested interface,哪怕它是 private 也可以。但是有一个前提,inner class instance 能够访问 enclosing class instace,因为并非所有的 inner class 都能访问的到,比如在声明在 static method 中的 local class。
相较之下,static nested class 的 instance 则是可以隔离 enclosing class 而独立存活的,但是它 cannot refer directly to instance variables or methods defined in its enclosing class
。
至此,对 nested class 和 inner class 的探索告一段落,虽然前前后后翻阅了不少的资料,修正了此前的片面理解,但是绝算不上深刻理解。最后用一朋友的签名来作结:越学越知道要学。