
5.14 内部类
5.14.1 内部类的基本定义
现在已经知道,在类内部可定义成员变量与方法,有趣的是,在类内部也可以定义另一个类。如果在类Outer的内部再定义一个类Inner,此时类Inner就称为内部类,而类Outer则称为外部类。
内部类可声明成public或private。当内部类声明成public或private时,对其访问的限制与成员变量和成员方法完全相同。下面列出了内部类的定义格式:
【格式5-8 内部类的声明格式】

下面就根据以上的格式定义一个内部类。
【例5.69】定义内部类

程序执行结果:

从上面的程序中可以清楚地发现,Inner类作为Outer类的内部类存在,并且在外部类的fun()方法之中直接实例化内部类的对象并调用方法print(),但是从上面的代码之中可以明显地发觉内部类的存在实际上已经破坏了一个类的基本结构,因为类是由属性及方法组成,所以这是内部类的一个缺点,那么内部类有哪些优点呢?如果现在读者把内部类拿到外面来就能发现内部类的优点,如下面代码。
【例5.70】将内部类拿到外部

程序执行结果:

以上的程序完成了内部类同样的功能,但是代码明显比之前的更加复杂,所以内部类的唯一好处就是可以方便地访问外部类中的私有属性。同时,外部类也可以方便地访问内部类中的私有属性,这样就可以避免封装所带来的操作结构复杂的问题。
5.14.2 使用static定义内部类
使用static可以声明属性或方法,而使用static也可以声明内部类,用static声明的内部类则变成外部类,但是用static声明的内部类不能访问非static的外部类属性。
【例5.71】使用static声明内部类

程序执行结果:

以上程序中将info属性定义成了static类型,这样程序中就可以通过static声明的内部类直接访问此static属性了,当然,如果此时info属性不是static类型的话,则编译时将出现以下的错误:

5.14.3 在外部访问内部类
一个内部类除了可以通过外部类访问,也可以直接在其他类中进行调用,调用的基本格式为:
【格式5-9 在外部访问内部类】

以上的操作格式中,首先要找到外部类的实例化对象之后,才可以通过外部类的实例化对象去实例化内部类的对象。
提示
观察内部类的class文件。
内部类定义之后,生成的class文件是以“Outer$Inner.class”的形式存在的,在Java中只要是在文件中看见了“$”,则在程序中使用将其替换为“.”。
【例5.72】在外部访问内部类

程序执行结果:

5.14.4 在方法中定义内部类
理论上,内部类可以定义在程序的任意位置,例如:代码块中、方法中,但是在方法中定义的内部类不能直接访问方法中的参数,如果方法中的参数想被内部类访问,则参数前必须加上final关键字。
【例5.73】在方法中定义内部类

程序执行结果:

本程序在fun()方法中定义有Inner的内部类,这样内部类就可以直接进行方法中变量的访问了。
提示
关于JDK 1.8的新支持。
从JDK 1.8开始由于引入了Lamda表达式的原因,所以对于内部类使用方法中的参数也发生了变化。在JDK 1.8以前的所有版本中,如果方法中的参数要想被内部类所访问,则参数前必须加上final关键字。

但是从JDK 1.8开始,此种规则被打破了,即使不加上final也可以正常使用。