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

图 1 内部类可以使用外部类的成员
内部类的实例一定要被绑定在外部类的实例上,如果从外部类中初始化一个内部类对象,那么内部类对象就会被绑定在外部类对象上。内部类初始化方式与其他类的初始化方式相同,都是使用 new 关键字。
【实例】首先创建 Car 类,Car 类中有私有属性 brand 和 start() 方法,然后在 Car 类的内部创建 Engine 类,Engine 类中有私有属性 model 和 ignite() 方法,最后输出“启动大众朗行,发动机 EA211 点火”。
成员内部类不止可以在外部类中使用,在其他类中也可以使用。在其他类中创建内部类对象的语法非常特殊,语法如下:
【实例】在项目中创建 TheSameName 类,在类中定义成员变量x,再定义一个内部类 Inner,在内部类中也创建 x 变量,并在内部类的 doit() 方法中定义一个局部变量 x。
【实例】创建一个抽象的狗类,类中有一个颜色属性和两个抽象方法,在测试类的主方法中创建抽象类对象,并用匿名内部类实现该对象的抽象方法。
使用匿名类时应该遵循以下原则:
匿名内部类编译以后,会产生以“外部类名$序号”为名称的.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 自增 } } }在类中,如果遇到内部类与外部类的成员变量重名的情况,则可以使用 this 关键字进行处理。例如,在内部类中使用 this.x 语句可以调用内部类的成员变量 x,而使用 TheSameName.this.x 语句可以调用外部类的成员变量 x,即使用外部类名称后跟一个点操作符和 this 关键字便可获取外部类的一个引用。
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 个匿名内部类。