在介绍区别之前,首先把概念理一下,Java 允许在一个类中定义另一个类,这样的类被称为嵌套类,而嵌套类又可分为四种:
静态嵌套类 - 声明为另一个类的静态成员
内部类 - 声明为另一个类的实例成员
本地内部类 - 声明在一个类的实例方法中
匿名内部类 - 类似本地内部类,但它是表达式,定义并返回一个只使用一次的对象
具体的用法,可以查看 Oracle 提供的 Java Tutorial 中的 [Classes and Objects] 这一节,这里就不在写了,下面看下各种嵌套类的特点和区别。
静态嵌套类
与类方法和字段一样,与外部类相关联
无法直接访问外部类的实例方法或字段
除了位于外部类的命名空间中,在行为上与普通顶级类无异
它更多的目的是为了方便打包
内部类
与实例方法和字段一样,与外部类的实例相关联
可以直接访问该实例的私有方法和字段
无法定义自己的任何静态成员
不能声明 interface,因为接口本质是静态的
本地内部类
它是在块中定义的类,块就是使用成对的大括号组成语句,比如 for 循环
类似内部类,非静态,可访问外部类的私有成员
此外可访问局部变量和参数,但它们必须为 final 类型
可以声明静态的常量变量
匿名内部类
主要提供更简洁和方便的代码来使用本地内部类,在声明一个类的同时并实例化
与本地内部类类似,可访问 final 类型的局部变量
与内部类类似,可访问外部类的私有成员
不能声明构造函数,但可以声明一个用于初始的块
此外可以声明字段、额外的方法和本地类
为什么使用嵌套类
使用嵌套类大概有三个原因:
逻辑分组 - 如果一个类只对另一个类有用,尤其是它不会在任何其他类中使用时,使用嵌套类是将两者是最合逻辑的。还能简化包结构,不必再新建一个文件
增强封装 - 有两个顶级类 A 和 B,其中 B 需要访问 A 中声明为 private 的成员,就可以通过将 B 嵌套在类 A 中实现,此外对于外面的世界 B 是隐藏的
代码更易读和可维护 - 嵌套使得代码更接近使用它的位置,带来更易读和可维护的代码
何时使用嵌套类、本地类、匿名类
当类只用于外部类并且它独立于外部类的(私有)成员时,使用静态嵌套类;如果需要访问外部类的私有成员时,则使用非静态嵌套类,即内部类。
比如,LinkedList 的 Node 嵌套类,它既不需要被外面的类访问,又不需要访问外部类的成员,所以它被声明成了静态嵌套类;而其中的 ListItr 迭代器实现类,它需要访问 LinkedList 内部受限的成员,所以声明成了内部类。
本地内部类,可以看作是 Java 提供的闭包,而匿名内部类可以看作是更方便的创建和使用本地内部类的方法,通常将其当作方法参数,用于回调。
常见与 GUI 编程中,比如,在监听窗口关闭事件时,会这样写 addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { TODO }});