在Java中,程序是由类构建而成的。而在一个类的内部也可以声明类,我们把这样的类叫做内部类,包裹内部类的称为外部类。在本节中,我们将多维度总结常用的内部类及其各自的特点和应用。

特点:

1、内部类定义为public时可以与文件名不同

2、内部类一旦编译成功,会成为完全不同的两类。outer.class 和 outer$inner.class 两类。(其中,outer和inner分别代表内、外部类)

3、内部类可以通过private修饰

4、通过内部类可以更好的体现封装以及代码编写的灵活性。

  • 当我们将内部类声明为private时,只有外部类可以访问,很好地隐藏了内部类信息。
  • 内部类可以继承(extends)或实现(implements)其他的类或接口,而不受外部类的影响。
  • 内部类可以直接访问外部类的字段和方法,即使是用private修饰的;而外部类则不能直接访问内部类的成员。
  • 内部类在实现线程调用或事件处理方面更加灵活(后续课程中会陆续介绍)

分类:

常见有成员内部类、方法内部类、静态内部类以及匿名内部类。

  1. 成员内部类:
  • 语法特点:

a. 定义在类内部,可以看成是外部类的一个成员,

b. 在成员内部类中无法声明静态属性/方法

c. 内部类在外部使用时,需要借由外部类信息才能完成实例化

d. 内部类的访问修饰符,可以任意,但是访问范围会受到影响

e. 内部类可以直接访问外部类的成员;如果出现同名属性/方法,优先访问内部类中定义的

f. 可以使用外部类.this.成员的方式,访问外部类中同名的信息

g. 外部类访问内部类信息,需要通过内部类实例,无法直接访问

  • 文件样式:

编译后分别生成 out.class 和 out$inner.class (其中,outer和inner分别代表内、外部类)

  • 应用场景:

当两个类(A,B)彼此之间需要相互访问,且对其中某一类的应用限制较高(譬如B只在A的某种特定应用时才需要),可以将B设置为A的成员内部类。

  1. 方法内部类:
  • 语法特点:

a. 定义在方法内部(也可以存在于代码块内部,此种应用较少),作用范围限定在方法内,也称为局部内部类

b. 和方法内部成员使用规则一样,class前面不可以添加public、private、protected、static

c. 类中不能包含静态成员

d. 类中可以包含final、abstract修饰的成员

e. 类中普通方法如需访问外部方法中的局部变量,则该变量也需定义为final(jdk1.8之后底层默认会给该变量加上final)

  • 文件样式:

编译后分别生成 out.class 和 out$1inner.class (其中,outer和inner分别代表内、外部类)

  • 应用场景:

由于类对象只能在当前方法或者代码块中创建、使用,相当于一次性产品,使用场景比较少。

  1. 静态内部类:
  • 语法特点:

a. 通过static修饰的内部类,也称为嵌套内部类,它无需依赖外部类对象构建实例。

b. 静态内部类中,只能直接访问外部类的静态成员,如果需要调用非静态成员,可以通过对象实例

c. 可以通过外部类.内部类.静态成员的方式,访问内部类中的静态成员

d. 当内部类属性与外部类属性同名时,默认直接调用内部类中的成员

e. 如果需要访问外部类中的静态属性,则可以通过 外部类.属性 的方式

f. 如果需要访问外部类中的非静态属性,则可以通过 new 外部类().属性的方式

  • 文件样式:

编译后分别生成 out.class 和 out$inner.class (其中,outer和inner分别代表内、外部类)

  • 应用场景:
    当类 A 需要使用类 B,而 B 并不需要直接访问外部类 A 的成员变量和方法时,可以将 B 作为 A 的静态内部类。
  1. 匿名内部类:
  • 语法特点:

a. 匿名内部类没有类名,没有class关键字,也无法产生具体类实例对象名

b. 必须继承或实现一个接口,指定给new的类型为匿名类的父类或父接口,但不能有显示的extends或implements子句。

c. 无法使用private、public、protected、abstract、static修饰

d. 无法编写构造方法,可以添加构造代码块

e. 类中不能出现静态成员

  • 文件样式:

编译后分别生成 out.class 和 out$1.class (其中,outer和inner分别代表内、外部类,当有多个匿名内部类时,数字依次递增)

  • 应用特点:

多可用于作为方法参数或者返回值,然后根据不同类型,无需产生具体类和对象名,返回不同的实现即可。