一篇文章带你搞清楚嵌套类!Java中四种嵌套类的深入解析

这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战

基本概念

  • 嵌套类 : nested classes, 在一个类的内部定义另一个类
  • 嵌套类有四种:
    • 静态成员类
    • 成员内部类
    • 局部内部类
    • 匿名内部类
  • 其中,成员内部类,方法内部类和匿名内部类都是非静态嵌套类
  • 嵌套类的特点:
    • 嵌套类可以访问外部类的所有数据成员和方法,包括私有成员和方法
    • 提高程序的可读性和维护性:
      • 因为如果一个类只对另一个类可用,那么将这两个类放在一起,更便于代码的理解和维护
    • 提高代码的封装性:
      • 给定两个类AB, 如果需要访问A类中的私有成员,则可以将B类封装在A类的内部
      • 这样不仅可以使得B类可以访问A类中的私有成员,并且可以在外部隐藏B
    • 减少代码的编写量

静态成员类

  • 静态成员类是一个声明在一个类内部的普通的类
  • 使用static修饰的嵌套类称作静态成员类,只能访问外部类的静态成员,不能直接访问外部类的非静态成员
  • 因为Java中规定静态方法不能直接访问非静态成员,所以在静态成员类中不能访问外部类的非静态成员
  • 对于外部类来说,整个静态内部类就是外部类成员.所以类成员只能访问类的对象属性和方法
  • 静态成员类示例

非静态成员类

  • 非静态成员类必须依赖于外部类的对象
  • 在非静态成员类中无法定义静态变量
  • 非静态成员类中隐式地保存了一个指向外部类对象的引用
  • 非静态成员类实例创建的时候,非静态成员类和外部类的关联关系也同时创建,并且这种关联关系无法修改. 这种关联关系需要消耗非静态成员类实例的空间,并且增加了构造时间开销
    • Map接口的实现通常使用非静态成员类实现集合视图
    • SetList接口的实现也使用非静态成员类实现迭代器
  • 非静态成员类示例

静态成员类和非静态成员类比较

  • 静态成员类和非静态成员类的区别:
    • 静态成员类可以有静态成员,可以声明static方法和变量. 非静态成员类不能有静态成员,不能声明静态static方法和变量
    • 静态成员类可以访问外部类的静态成员变量,不可以访问外部类的非静态成员变量
    • 非静态成员类的实例可以调用外部类的方法和属性
    • 静态成员类可以独立存在,即使外部类消亡,静态成员类还是可以存在的. 非静态成员类与外部类是依赖关系,内部成员类的实例不能脱离外部类,一起声明,一起回收
  • 如果声明成员类不要求访问外部类的实例,就始终要将static修饰符放在声明中,作为静态成员类
  • 如果不使用static修饰符就是非静态成员类,则每个实例都会包含一个额外的指向外部类对象的引用.这样不仅消耗空间和时间,并且会导致外部类的实例在符合垃圾回收机制时仍然保留

局部内部类

  • 内部类: 将类放在方法或者某个作用域内
  • 方法内部类的特点:
    • 局部内部类不能在类外或者类的其余方法中访问
    • 局部内部类只能在方法内部,局部内部类定义之后才能使用,不存在内部可见性问题,因此没有访问修饰符
    • 局部内部类只能在定义方法内部类的方法内实例化,不可以在方法外进行实例化
    • 局部内部类中可以访问外部类的成员变量. 如果方法是static方法,那么只能访问外部类的静态成员变量
    • 局部内部类可以使用final或者abstract修饰符修饰
    • 局部内部类的对象只能使用定义方法内部类的方法中的final修饰符的局部变量
      • 因为方法的局部变量位于堆栈之上,只存在于该方法的生命周期之内.当一个方法结束,方法的方法的栈结构被回收删除,局部变量就不存在了
      • 但是在方法内创建的局部内部类对象可能仍然保存在堆中. 比如对局部内部类的引用保存在其余的类对象的成员变量中
      • 因为无法保证局部变量和局部内部类对象的存活期一样长,所以在局部内部类对象中不能使用方法的非final修饰的局部变量
  • 局部内部类示例

匿名内部类

  • 匿名内部类: 没有名字的内部类
    • 匿名内部类不是外部类的一个成员
    • 匿名内部类不会与外部类中其余成员一起声明,而是在运行时进行声明和实例化
  • 当且仅当匿名内部类在非静态状态下,才会有外部类实例.但是即使出现在静态状态下,也不会拥有静态成员
  • 匿名内部类的使用场景:
    • 常见的动态函数对象: 事件监听器
    • 创建过程对象: Runnable, Thread或者TimerTask
    • 静态工厂方法内部: return new xXx();

继承式匿名内部类

接口式匿名内部类

参数式匿名内部类

Guess you like

Origin juejin.im/post/7054205222713262093