Java内部类的用法(附带实例)
我们在前面的学习过程中,在一个文件中定义两个类,并且其中任何一个类都不在另一个类的内部。如果在类中再定义一个类,则将在类中再定义的那个类称为内部类。
成员内部类和匿名类是最常见的内部类,本节将对这两种内部类进行讲解。

图 1 内部类可以使用外部类的成员
内部类的实例一定要被绑定在外部类的实例上,如果从外部类中初始化一个内部类对象,那么内部类对象就会被绑定在外部类对象上。内部类初始化方式与其他类的初始化方式相同,都是使用 new 关键字。
【实例】首先创建 Car 类,Car 类中有私有属性 brand 和 start() 方法,然后在 Car 类的内部创建 Engine 类,Engine 类中有私有属性 model 和 ignite() 方法,最后输出“启动大众朗行,发动机 EA211 点火”。
运行结果如下:
成员内部类不止可以在外部类中使用,在其他类中也可以使用。在其他类中创建内部类对象的语法非常特殊,语法如下:
【实例】在项目中创建 TheSameName 类,在类中定义成员变量x,再定义一个内部类 Inner,在内部类中也创建 x 变量,并在内部类的 doit() 方法中定义一个局部变量 x。
在类中,如果遇到内部类与外部类的成员变量重名的情况,则可以使用 this 关键字进行处理。例如,在内部类中使用 this.x 语句可以调用内部类的成员变量 x,而使用 TheSameName.this.x 语句可以调用外部类的成员变量 x,即使用外部类名称后跟一个点操作符和 this 关键字便可获取外部类的一个引用。
【实例】创建一个抽象的狗类,类中有一个颜色属性和两个抽象方法,在测试类的主方法中创建抽象类对象,并用匿名内部类实现该对象的抽象方法。
运行结果如下:
使用匿名类时应该遵循以下原则:
匿名内部类编译以后,会产生以“外部类名$序号”为名称的.class文件,序号以 1~n 排列,分别代表 1~n 个匿名内部类。
成员内部类和匿名类是最常见的内部类,本节将对这两种内部类进行讲解。
Java成员内部类
在一个类中使用内部类,可以在内部类中直接存取其所在类的私有成员变量。成员内部类的语法如下:class OuterClass { //外部类 class InnerClass { //内部类 } }在成员内部类中可以随意使用外部类的成员方法及成员变量,尽管这些类成员被修饰为 private。下图充分说明了内部类的使用,尽管成员变量 i 以及成员方法 g() 都在外部类中被修饰为 private,但在成员内部类中可以直接使用。

图 1 内部类可以使用外部类的成员
内部类的实例一定要被绑定在外部类的实例上,如果从外部类中初始化一个内部类对象,那么内部类对象就会被绑定在外部类对象上。内部类初始化方式与其他类的初始化方式相同,都是使用 new 关键字。
【实例】首先创建 Car 类,Car 类中有私有属性 brand 和 start() 方法,然后在 Car 类的内部创建 Engine 类,Engine 类中有私有属性 model 和 ignite() 方法,最后输出“启动大众朗行,发动机 EA211 点火”。
- public class Car { // 创建汽车类
- private String brand; // 汽车品牌
- public Car(String brand) { // 汽车类的构造方法,参数为汽车品牌
- this.brand = brand; // 给汽车品牌赋值
- }
- class Engine { // 发动机类(内部类)
- String model; // 发动机型号
- public Engine(String model) { // 发动机类的构造方法,参数为发动机型号
- this.model = model; // 给发动机型号赋值
- }
- public void ignite() { // (发动机)点火方法
- System.out.println("发动机" + this.model + "点火");
- }
- }
- public void start() { // 启动(汽车)方法
- System.out.println("启动" + this.brand);
- }
- public static void main(String[] args) {
- Car car = new Car("大众朗行"); // 创建汽车类对象,并为汽车品牌赋值
- car.start(); // 汽车类对象调用启动(汽车)方法
- // 创建发动机类(内部类)对象,并为发动机型号赋值
- Car.Engine engine = car.new Engine("EA211");
- engine.ignite(); // 发动机类对象调用(发动机)点火方法
- }
- }
启动大众朗行
发动机EA211点火
成员内部类不止可以在外部类中使用,在其他类中也可以使用。在其他类中创建内部类对象的语法非常特殊,语法如下:
外部类 outer = new 外部类();
外部类.内部类 inner = outer.new 内部类();
- 如果在外部类和非静态方法之外实例化内部类对象,需要使用"外部类.内部类"的形式指定该对象的类型。
- 内部类对象会依赖于外部类对象,除非已经存在一个外部类对象,否则类中不会出现内部类对象。
使用this关键字获取内部类与外部类的引用
如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用 this 关键字。【实例】在项目中创建 TheSameName 类,在类中定义成员变量x,再定义一个内部类 Inner,在内部类中也创建 x 变量,并在内部类的 doit() 方法中定义一个局部变量 x。
- public class TheSameName {
- private int x = 7; // 外部类的 x
- private class Inner {
- private int x = 9; // 内部类的 x
- public void doIt() {
- int x = 11; // 局部变量 x
- x++; // 局部变量 x 自增
- this.x++; // 调用内部类的 x 自增
- TheSameName.this.x++; // 调用外部类的 x 自增
- }
- }
- }
Java匿名内部类
匿名类是只在创建对象时才会编写类体的一种写法。匿名类的特点是“现用现写”,其语法如下:new 父类/父接口() { 子类实现的内容 };
注意,最后一个大括号之后有分号。
【实例】创建一个抽象的狗类,类中有一个颜色属性和两个抽象方法,在测试类的主方法中创建抽象类对象,并用匿名内部类实现该对象的抽象方法。
- abstract class Dog {
- String Color;
- public abstract void move();
- public abstract void call();
- }
- public class Demo {
- public static void main(String args[]) {
- Dog maomao = new Dog() {
- public void move() {
- System.out.println("四腿狂奔");
- }
- public void call() {
- System.out.println("嗷呜~");
- }
- };
- maomao.Color = "灰色";
- maomao.move();
- maomao.call();
- }
- }
四腿狂奔
嗷呜~
使用匿名类时应该遵循以下原则:
- 匿名类不能写构造方法;
- 匿名类不能定义静态的成员;
- 如果匿名类创建的对象没有赋值给任何引用变量,会导致该对象用完一次就会被 Java 虚拟机销毁。
匿名内部类编译以后,会产生以“外部类名$序号”为名称的.class文件,序号以 1~n 排列,分别代表 1~n 个匿名内部类。