Android开发中,很多情况下都要用到内部类,在使用的过程中,偶尔可能遇到内部类嵌套内部类、内部类嵌套interface,甚至interface嵌套内部类等奇特场景,在嵌套调用一些成员静态或非静态的成员变量时编译器可能会报错,大部分人会根据IDE的提示来规避这些错误,修改编译运行后ok就算过了,至于为什么语法规则这样定,很少有人去了解。
本文就针对java中静态内部类的语法规则做出一个分析
在分析语法前,我们要区分一下静态内部类和非静态内部类的区别:
-
对于静态内部类,它不依赖于外部类对象,其内部类也是可以有非静态成员的,它对象的存储空间中,并没有指向外部类对象的引用。所以,在静态内部类中,不能直接访问外部类的非静态成员,只能访问外部类的静态成员。而外部类能访问静态内部类的静态成员,但是不能直接访-问静态内部类的非静态成员。
-
对于非静态内部类,其对象的空间中,保留了一个指向外部类对象的指针,这就意味着要创建非静态的内部类,必须先要有外部类对象,所以,非静态的内部类是可以直接引用外部类的成员的。
搞清楚区别后我们再分析下使用内部类报错的一个场景:
在一个class中定义一个内部类,之后在这个内部类中定义一个interface,IDE会报错The member interface xxx can only be defined inside a top-level class or interface or in a static
翻译过来就是:interface作为成员的话只能够被定义在最外层,或者在静态上下文中。看不懂啊有木有,那就看一下例子:
context
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
通过上面的例子,可以看到一个interface在class中被定义有以下几种情况:
- 在outerclass或者outerinterface内被定义(Top-level)->编译ok
- 在innerclass内部被定义(non-Top-level)->编译error
- 在static修饰的innerclass内部被定义->编译ok
这就有一个问题了,为什么静态内部类中可以定义interface,而非静态的内部类中不能定义interface呢?
为此我专门看了一下oracle的官方文档中对内部类的定义说明,地址如下Inner Classes and Enclosing Instances 其中有这样三句话指点了我:
An inner class may be a non-static member class, a local class, or an anonymous class. A member class of an interface is implicitly static so is never considered to be an inner class.
…
It is a compile-time error if an inner class declares a member that is explicitly or implicitly static, unless the member is a constant variable
…
A nested class that is not an inner class may declare static members freely, in accordance with the usual rules of the Java programming language.
翻译->
第一句:一个内部类可以是类的非静态的成员类,或局部类,再或者是一个匿名类。而interfce是一个隐式的static成员类,是不能被认为成内部类的。
第二句:如果一个内部类中声明的一个成员是static的,编译就会报错,除非这个成员是被static和final共同修饰的常量。
第三句:按照java的语法规则,一个嵌套类被声明为static的话就不是一个内部类了
总结:java的语法规定了非静态的内部类才叫做内部类,而静态内部类只能叫做静态嵌套类,由于interface隐式的被static修饰,而在内部类中除非声明那种static final类型的常量,声明其余的static类型的成员(包括interface)都是不符合java语法规则的。这就解释了为什么至于内部类中不能声明interface而添加了static的内部类又能使用声明的疑问。