Java 嵌套类

嵌套类, 是嵌套在 Java 一个类的内部的类.

嵌套类可以通过两种形式来声明:

  1. 使用 static 修饰的嵌套类, 我们称之为静态嵌套类(Static Nested Class)
  2. 不使用 static 修饰的嵌套类, 我们称之为内部类(Inner Class) 或 非静态嵌套类 (Non-Static Nested Class)

因此, 嵌套类的定义有以下两种形式:

class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}

嵌套类是它的封闭类(外部类)的成员,其中内部类(非静态嵌套类)可以访问其外部类的其他成员,包括私有成员. 静态嵌套类则不具备这样的能力.

嵌套类可以使用 public, private, protected 及默认修饰符修饰, 而普通类只能声明为共有和包私有.

为什么要使用嵌套类

使用嵌套类, 有以下原因:

  1. 使包的结构更加简洁, 如果一个类仅对另一个类有用, 那么使用嵌套类是合乎逻辑的.
  2. 提供了更丰富的封装方式, 基于嵌套类的访问修饰符, 我们可以做到更细致的访问控制.
  3. 引导提升代码的可读性和可维护性, 嵌套类与外部类的位置更靠近了.

静态嵌套类的调用

静态嵌套类可以通过外部类名来调用, 通用示例如下:

OuterClass.StaticNestedClass

初始化示例如下:

OuterClass.StaticNestedClass nestedClass = new OuterClass.StaticNestedClass()

内部类的调用

内部类则必须通过外部类的实例来调用了, 初始化方法如下:

OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();

需要注意的是 这里的 new 是放在 OuterClass 的示例对象 outerClass 后的. 

内部类调用外部类的其他成员

首先我们定义一个带有内部类 Engine 的外部类 Yi21Car, 定义如下:

package com.yi21.course;

public class Yi21Car {

    //油量 L
    private double oil = 0;

    private Engine engine;

    private class Engine {
        private final double EVERY_TIME = 0.01;
        //烧油
        public void burn() {
            if (oil < EVERY_TIME) {
                throw new RuntimeException("No Gas!");
            }
            oil -= EVERY_TIME;
        }
    }

    public Yi21Car(double oil) {
        this.oil = oil;
        engine = new Engine();
    }

    public void stepAccelerator() {
        engine.burn();
    }

    public double getRestOil() {
return oil; } }

我们的定义如下:

  • 定义外部类 - 汽车类: Yi21Car
  • 定义了属性 oil, 表示汽车的汽油量
  • 定义了一个内部类, 汽车的引擎 Engine
  • Engine 定义了一个 burn() 方法, 表示烧油, 为了简化过程, 我们规定每次都烧 0.01 L 汽油, 如果汽油不够就抛出异常, 表示没油了.
  • 再定义了 Yi21Car 的构造方法, 构造方法中, 设定了车的汽油存量 oil 以及初始化了内部类 Engine.
  • 定义外部类的方法 stepAccelerator() 表示踩油门, 踩油门真实的汽车当然会做很多工作, 但我们在此错了简化, 只有发动机烧油, 于是调用了 engineblur() 方法.
  • 最后声名了 getRestOil() 方法, 用于查看剩多少油.

然后我们在外部通过以下方法调用:

Yi21Car car = new Yi21Car(50);
car.stepAccelerator();
System.out.println(car.getRestOil());
car.stepAccelerator();
System.out.println(car.getRestOil());
car.stepAccelerator();
System.out.println(car.getRestOil());

初始化一辆车 Yi21Car, 然后踩三次油门, 分别看看还剩多少油, 结果如下:

49.99
49.980000000000004
49.970000000000006

由此我们可知, 内部类 Engine 完成了对外部类 Yi21Car 的成员变量 oil 的访问.

当时需要注意的是, 如果 Engine 内部也定义 了一个 oil 成员变量, 那么再通过 Engine 访问 oil 的话访问的就是 Engineoil 了, 而不是 Yi21Caroil 了. 那如果我想通过内部类, 访问外部类的同名成员要怎么办呢? 两个方法:

  1. 避免内部类的外部的成员同名
  2. 通过 外部类的类名 + .this 调用, 比如 Yi21Car.this.oil

序列化

在运行时反编译序列化的内部类可能会存在兼容性的问题, 因此强烈不建议对内部类(包括本地类和匿名类进行)进行序列化.

以上就是 Java 嵌套类的全部内容.

下一节请看: Java 运算符