1. 嵌套类
Java一个文件中除了有最顶层的类,在类内部还可以定义新的类。之所以这样设计有三点原因
- 能够符合逻辑的编排那些只在一个地方用到的类
- 能够提高封装性,因为嵌套类可以对外隐藏但对内访问外部类的成员
- 可以让代码更好阅读和维护。。。。(这一点我觉得有待商榷)
嵌套类有多种形式,第一种是内部类,又分为静态内部类,和非静态内部类;第二种是本地类,出现在{}
中,一般是出现在函数、循环等;第三种是匿名类,用语句来表示。本地类和匿名类实际上是两种特殊的内部非静态类。
2. 内部类
内部类需要了解声明,实例化方式,与外部类成员之间的关系,和序列化的一些知识点。
内部类的访问控制修饰符与类中的成员修饰符一致,有四种,具体的访问控制范围也是一致的。
//static inner class
class OuterClass{
modifier static class InnerClass{}
}
//non-static inner class
class OuterClass{
modifier class InnerClass{}
}
内部类的数量有限制吗?语言本身应该是没有限制的,但是在编译过程中,会通过类决定class的文件名,此时文件名长度限制会对内部类的层数有一定的限制,但对内部类的数量会不会有限制还没仔细看
。
2.1 内部静态类
内部静态类所有的功能都和外部类相同,只是为了编排需求放在内部。声明形式如上,实例化方式如下:
OuterClass.InnerClass innerInstance = new OuterClass.InnerClass();
内部静态类只能直接访问外部静态类的静态变量(所有的类都能,只要满足访问控制权限),但不能访问实例变量。
2.2 内部非静态类
内部非静态类是与实例绑定在一起的,只能通过实例进行实例化,声明形式如上,实例化方式如下:
OuterClass.InnerClass innerInstance = outerInstance.new InnerClass();
既然是与实例绑定在一起的,那么也是可以访问外部类的实例成员的。
(反射这一部分还没有仔细看)不能对内部非静态类进行序列化,因为不同的编译器对内部非静态类的序列化方式不一样,所以反序列化的时候,对于不同编译器编译的非静态类可能会出现问题?
既然内部非静态类持有对外部类的引用,那么内部非静态类一定不会在外部类之后被gc了。
3 局域类
局域类为{}
内的类,例如:
public void method(){
class LocalClass{}
}
局域类不可以在外部进行实例,可以在方法内部进行实例化。
局域类可以访问局域变量以及实例变量,但是如果局域类在静态方法中就不可以访问实例变量,可以理解为这不是局域类的限制,而是静态方法的限制。
同时,在访问局域变量或者参数变量的时候,变量需要是final修饰的,或者方法体当中没有对进行修改的。这是因为局域类访问局部变量
的时候是通过变量捕捉(找了半天,原来变量捕捉就是复制一份变量)访问变量,所以如果变量本身修改了,但是没有修改局域类中的变量值,就不统一了。这是对局域变量和参数变量的限制,对实例变量没有这样的限制。
局域类不可以声明为静态类,这主要是因为局域类可以访问实例变量,需要持有实例的引用(未经考证)。而且局域类中不能定义静态成员,除了常量。大概原因是(没有仔细考究)java运行的时候需要对静态成员进行加载,但是局域类根据实例绑定在一起,所以不对局域类实例化,就无法确定静态成员啥的。
4 匿名类
匿名类可以用来定义接口或者继承类。匿名类的使用方式为实例化一个对象并赋值给一个显示引用或者作为参数:
interface SayHello{}
class AnonClass{}
SayHello sayHello = new SayHello(){}
AnonClass anonClass = new AnonClass(){}
object.method(new interface/class(){})
匿名类对于外部类的成员访问与局域类相同。