首页 > 编程笔记 > Java笔记 阅读:16

Java内部类的用法(附带实例)

通义灵码
我们在前面的学习过程中,在一个文件中定义两个类,并且其中任何一个类都不在另一个类的内部。如果在类中再定义一个类,则将在类中再定义的那个类称为内部类。

成员内部类和匿名类是最常见的内部类,本节将对这两种内部类进行讲解。

Java成员内部类

在一个类中使用内部类,可以在内部类中直接存取其所在类的私有成员变量。成员内部类的语法如下:
class OuterClass {        //外部类
    class InnerClass {    //内部类
    }
}
在成员内部类中可以随意使用外部类的成员方法及成员变量,尽管这些类成员被修饰为 private。下图充分说明了内部类的使用,尽管成员变量 i 以及成员方法 g() 都在外部类中被修饰为 private,但在成员内部类中可以直接使用。


图 1 内部类可以使用外部类的成员

内部类的实例一定要被绑定在外部类的实例上,如果从外部类中初始化一个内部类对象,那么内部类对象就会被绑定在外部类对象上。内部类初始化方式与其他类的初始化方式相同,都是使用 new 关键字。

【实例】首先创建 Car 类,Car 类中有私有属性 brand 和 start() 方法,然后在 Car 类的内部创建 Engine 类,Engine 类中有私有属性 model 和 ignite() 方法,最后输出“启动大众朗行,发动机 EA211 点火”。
  1. public class Car { // 创建汽车类
  2. private String brand; // 汽车品牌
  3. public Car(String brand) { // 汽车类的构造方法,参数为汽车品牌
  4. this.brand = brand; // 给汽车品牌赋值
  5. }
  6. class Engine { // 发动机类(内部类)
  7. String model; // 发动机型号
  8. public Engine(String model) { // 发动机类的构造方法,参数为发动机型号
  9. this.model = model; // 给发动机型号赋值
  10. }
  11. public void ignite() { // (发动机)点火方法
  12. System.out.println("发动机" + this.model + "点火");
  13. }
  14. }
  15. public void start() { // 启动(汽车)方法
  16. System.out.println("启动" + this.brand);
  17. }
  18. public static void main(String[] args) {
  19. Car car = new Car("大众朗行"); // 创建汽车类对象,并为汽车品牌赋值
  20. car.start(); // 汽车类对象调用启动(汽车)方法
  21. // 创建发动机类(内部类)对象,并为发动机型号赋值
  22. Car.Engine engine = car.new Engine("EA211");
  23. engine.ignite(); // 发动机类对象调用(发动机)点火方法
  24. }
  25. }
运行结果如下:

启动大众朗行
发动机EA211点火


成员内部类不止可以在外部类中使用,在其他类中也可以使用。在其他类中创建内部类对象的语法非常特殊,语法如下:

外部类 outer = new 外部类();
外部类.内部类 inner = outer.new 内部类();

注意:

使用this关键字获取内部类与外部类的引用

如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用 this 关键字。

【实例】在项目中创建 TheSameName 类,在类中定义成员变量x,再定义一个内部类 Inner,在内部类中也创建 x 变量,并在内部类的 doit() 方法中定义一个局部变量 x。
  1. public class TheSameName {
  2. private int x = 7; // 外部类的 x
  3.  
  4. private class Inner {
  5. private int x = 9; // 内部类的 x
  6. public void doIt() {
  7. int x = 11; // 局部变量 x
  8. x++; // 局部变量 x 自增
  9. this.x++; // 调用内部类的 x 自增
  10. TheSameName.this.x++; // 调用外部类的 x 自增
  11. }
  12. }
  13. }
在类中,如果遇到内部类与外部类的成员变量重名的情况,则可以使用 this 关键字进行处理。例如,在内部类中使用 this.x 语句可以调用内部类的成员变量 x,而使用 TheSameName.this.x 语句可以调用外部类的成员变量 x,即使用外部类名称后跟一个点操作符和 this 关键字便可获取外部类的一个引用。

Java匿名内部类

匿名类是只在创建对象时才会编写类体的一种写法。匿名类的特点是“现用现写”,其语法如下:
new 父类/父接口() {
    子类实现的内容
};

注意,最后一个大括号之后有分号。


【实例】创建一个抽象的狗类,类中有一个颜色属性和两个抽象方法,在测试类的主方法中创建抽象类对象,并用匿名内部类实现该对象的抽象方法。
  1. abstract class Dog {
  2. String Color;
  3. public abstract void move();
  4. public abstract void call();
  5. }
  6.  
  7. public class Demo {
  8. public static void main(String args[]) {
  9. Dog maomao = new Dog() {
  10. public void move() {
  11. System.out.println("四腿狂奔");
  12. }
  13. public void call() {
  14. System.out.println("嗷呜~");
  15. }
  16. };
  17. maomao.Color = "灰色";
  18. maomao.move();
  19. maomao.call();
  20. }
  21. }
运行结果如下:

四腿狂奔
嗷呜~

从这个结果中可以看出,本来无法创建对象的抽象类竟然也可以出现在 new 关键字的右侧。为何叫匿名内部类?就是因为实例中 Dog 抽象类的实现类没有名称。创建出的对象 maomao 既不是金毛犬,也不是哈士奇犬,在程序中 maomao 只能被解读为“一只具体的无名之狗”。

使用匿名类时应该遵循以下原则:
匿名内部类编译以后,会产生以“外部类名$序号”为名称的.class文件,序号以 1~n 排列,分别代表 1~n 个匿名内部类。

相关文章