# 嵌套类

> 原文： [https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html](https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html)

Java 编程语言允许您在另一个类中定义类。这样的类称为 _ 嵌套类 _，如下所示：

```
class OuterClass {
    ...
    class NestedClass {
        ...
    }
}

```

* * *

**Terminology:** Nested classes are divided into two categories: static and non-static. Nested classes that are declared `static` are called _static nested classes_. Non-static nested classes are called _inner classes_.

* * *

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

```

嵌套类是其封闭类的成员。非静态嵌套类（内部类）可以访问封闭类的其他成员，即使它们被声明为私有。静态嵌套类无权访问封闭类的其他成员。作为`OuterClass`的成员，可以将`private`，`public`，`protected`或 _ 包私有 _ 声明为嵌套类。 （回想外部类只能声明`public`或 _ 包私有 _。）

## 为什么使用嵌套类？

使用嵌套类的令人信服的理由包括：

*   **这是一种逻辑分组仅在一个地方使用的类的方法**：如果一个类只对另一个类有用，那么将它嵌入该类并将两者保持在一起是合乎逻辑的。嵌套这样的“帮助类”使得它们的包更加简化。

*   **它增加了封装**：考虑两个顶级类 A 和 B，其中 B 需要访问 A 的成员，否则将被声明为`private`。通过将类 B 隐藏在类 A 中，可以将 A 的成员声明为私有，并且 B 可以访问它们。另外，B 本身可以隐藏在外面。

*   **它可以带来更易读和可维护的代码**：在顶级类中嵌套小类会使代码更接近于使用它的位置。

## 静态嵌套类

与类方法和变量一样，静态嵌套类与其外部类相关联。和静态类方法一样，静态嵌套类不能直接引用其封闭类中定义的实例变量或方法：它只能通过对象引用来使用它们。

* * *

**Note:** A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class. In effect, a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience.

* * *

使用封闭的类名访问静态嵌套类：

```
OuterClass.StaticNestedClass

```

例如，要为静态嵌套类创建对象，请使用以下语法：

```
OuterClass.StaticNestedClass nestedObject =
     new OuterClass.StaticNestedClass();

```

## 内在的类

与实例方法和变量一样，内部类与其封闭类的实例相关联，并且可以直接访问该对象的方法和字段。此外，由于内部类与实例相关联，因此无法定义任何静态成员本身。

作为内部类实例的对象在中存在 _ 外部类的实例。考虑以下类：_

```
class OuterClass {
    ...
    class InnerClass {
        ...
    }
}

```

`InnerClass`的实例只能存在于`OuterClass`的实例中，并且可以直接访问其封闭实例的方法和字段。

要实例化内部类，必须首先实例化外部类。然后，使用以下语法在外部对象中创建内部对象：

```
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

```

有两种特殊的内部类：[本地类](localclasses.html)和[匿名类](anonymousclasses.html)。

如果特定范围（例如内部类或方法定义）中的类型声明（例如成员变量或参数名称）与封闭范围中的另一个声明具有相同的名称，则声明 _shadow_ 封闭范围的声明。您不能仅通过其名称引用带阴影的声明。以下示例 [`ShadowTest`](examples/ShadowTest.java) 演示了这一点：

```

public class ShadowTest {

    public int x = 0;

    class FirstLevel {

        public int x = 1;

        void methodInFirstLevel(int x) {
            System.out.println("x = " + x);
            System.out.println("this.x = " + this.x);
            System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
        }
    }

    public static void main(String... args) {
        ShadowTest st = new ShadowTest();
        ShadowTest.FirstLevel fl = st.new FirstLevel();
        fl.methodInFirstLevel(23);
    }
}

```

以下是此示例的输出：

```
x = 23
this.x = 1
ShadowTest.this.x = 0
```

此示例定义了三个名为`x`的变量：类`ShadowTest`的成员变量，内部类`FirstLevel`的成员变量，以及方法`methodInFirstLevel`中的参数。定义为方法`methodInFirstLevel`参数的变量`x`会影响内部类`FirstLevel`的变量。因此，在方法`methodInFirstLevel`中使用变量`x`时，它指的是方法参数。要引用内部类`FirstLevel`的成员变量，请使用关键字`this`来表示封闭范围：

```
System.out.println("this.x = " + this.x);
```

请参阅通过它们所属的类名包含较大范围的成员变量。例如，以下语句从方法`methodInFirstLevel`访问类`ShadowTest`的成员变量：

```
System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
```

[强烈建议不要使用内部类的序列化](../../jndi/objects/serial.html)，包括[本地](localclasses.html)和[匿名](anonymousclasses.html)类。当 Java 编译器编译某些构造时，例如内部类，它会创建 _ 合成构造 _;这些是类，方法，字段和其他在源代码中没有相应构造的构造。合成构造使 Java 编译器能够在不更改 JVM 的情况下实现新的 Java 语言功能。但是，合成构造在不同的 Java 编译器实现中可能不同，这意味着`.class`文件也可以在不同的实现之间变化。因此，如果序列化内部类，然后使用不同的 JRE 实现反序列化，则可能存在兼容性问题。有关在编译内部类时生成的合成构造的更多信息，请参见[获取方法参数名称](../../reflect/member/methodparameterreflection.html)一节中的[隐式和合成参数](../../reflect/member/methodparameterreflection.html#implcit_and_synthetic)部分。