这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战
基本概念
- 嵌套类 : nested classes, 在一个类的内部定义另一个类
- 嵌套类有四种:
- 静态成员类
- 成员内部类
- 局部内部类
- 匿名内部类
- 其中,成员内部类,方法内部类和匿名内部类都是非静态嵌套类
- 嵌套类的特点:
- 嵌套类可以访问外部类的所有数据成员和方法,包括私有成员和方法
- 提高程序的可读性和维护性:
- 因为如果一个类只对另一个类可用,那么将这两个类放在一起,更便于代码的理解和维护
- 提高代码的封装性:
- 给定两个类A和B, 如果需要访问A类中的私有成员,则可以将B类封装在A类的内部
- 这样不仅可以使得B类可以访问A类中的私有成员,并且可以在外部隐藏B类
- 减少代码的编写量
静态成员类
- 静态成员类是一个声明在一个类内部的普通的类
- 使用static修饰的嵌套类称作静态成员类,只能访问外部类的静态成员,不能直接访问外部类的非静态成员
- 因为Java中规定静态方法不能直接访问非静态成员,所以在静态成员类中不能访问外部类的非静态成员
- 对于外部类来说,整个静态内部类就是外部类成员.所以类成员只能访问类的对象属性和方法
- 静态成员类示例
非静态成员类
- 非静态成员类必须依赖于外部类的对象
- 在非静态成员类中无法定义静态变量
- 非静态成员类中隐式地保存了一个指向外部类对象的引用
- 非静态成员类实例创建的时候,非静态成员类和外部类的关联关系也同时创建,并且这种关联关系无法修改. 这种关联关系需要消耗非静态成员类实例的空间,并且增加了构造时间开销
- Map接口的实现通常使用非静态成员类实现集合视图
- Set和List接口的实现也使用非静态成员类实现迭代器
- 非静态成员类示例
静态成员类和非静态成员类比较
- 静态成员类和非静态成员类的区别:
- 静态成员类可以有静态成员,可以声明static方法和变量. 非静态成员类不能有静态成员,不能声明静态static方法和变量
- 静态成员类可以访问外部类的静态成员变量,不可以访问外部类的非静态成员变量
- 非静态成员类的实例可以调用外部类的方法和属性
- 静态成员类可以独立存在,即使外部类消亡,静态成员类还是可以存在的. 非静态成员类与外部类是依赖关系,内部成员类的实例不能脱离外部类,一起声明,一起回收
- 如果声明成员类不要求访问外部类的实例,就始终要将static修饰符放在声明中,作为静态成员类
- 如果不使用static修饰符就是非静态成员类,则每个实例都会包含一个额外的指向外部类对象的引用.这样不仅消耗空间和时间,并且会导致外部类的实例在符合垃圾回收机制时仍然保留
局部内部类
- 内部类: 将类放在方法或者某个作用域内
- 方法内部类的特点:
- 局部内部类不能在类外或者类的其余方法中访问
- 局部内部类只能在方法内部,局部内部类定义之后才能使用,不存在内部可见性问题,因此没有访问修饰符
- 局部内部类只能在定义方法内部类的方法内实例化,不可以在方法外进行实例化
- 局部内部类中可以访问外部类的成员变量. 如果方法是static方法,那么只能访问外部类的静态成员变量
- 局部内部类可以使用final或者abstract修饰符修饰
- 局部内部类的对象只能使用定义方法内部类的方法中的final修饰符的局部变量
- 因为方法的局部变量位于堆栈之上,只存在于该方法的生命周期之内.当一个方法结束,方法的方法的栈结构被回收删除,局部变量就不存在了
- 但是在方法内创建的局部内部类对象可能仍然保存在堆中. 比如对局部内部类的引用保存在其余的类对象的成员变量中
- 因为无法保证局部变量和局部内部类对象的存活期一样长,所以在局部内部类对象中不能使用方法的非final修饰的局部变量
- 局部内部类示例
匿名内部类
- 匿名内部类: 没有名字的内部类
- 匿名内部类不是外部类的一个成员
- 匿名内部类不会与外部类中其余成员一起声明,而是在运行时进行声明和实例化
- 当且仅当匿名内部类在非静态状态下,才会有外部类实例.但是即使出现在静态状态下,也不会拥有静态成员
- 匿名内部类的使用场景:
- 常见的动态函数对象: 事件监听器
- 创建过程对象: Runnable, Thread或者TimerTask
- 静态工厂方法内部: return new xXx();
继承式匿名内部类
接口式匿名内部类
- 接口式匿名内部类不是实例化接口,而是实现了一个接口的匿名内部类
- 接口式匿名内部类示例