内部类和静态嵌套类
2025-01-22 08:19:30    1.2k 字   
This post is also available in English and alternative languages.

Java中允许我们在一个类(A)中定义另一个类(b),这样的类(b)被称作:内部类(嵌套类)。

内部类(嵌套类)可以分为两类:静态嵌套类内部类


1. 内部类(嵌套类) 和 静态嵌套类

在Oracle官方文档中有这么一句:

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.

术语:嵌套类分为两类:静态和非静态。 声明为静态的嵌套类称为静态嵌套类。 非静态嵌套类称为内部类。

二者如何理解?

借用知乎上的回答(非常形象):

什么是嵌套?
嵌套就是我跟你没关系,自己可以完全独立存在,但是我就想借你的壳用一下,来隐藏一下我自己。

什么是内部?
内部就是我是你的一部分,我了解你,我知道你的全部,没有你就没有我。(所以内部类对象是以外部类对象存在为前提的)


1.1. 内部类

内部类 是封闭类(外部类)的成员,例如:NestedClass 内部类是 OuterClass 的成员。

内部类 可以访问 封闭类的其他成员,即使 其他成员 也被声明为私有。

1
2
3
4
5
6
class OuterClass {
//...
class NestedClass {
//...
}
}

1.1.1. 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
public class AppTest {
public static void main(String[] args) {
RollsRoyce rollsRoyce = new RollsRoyce("罗尔斯-罗伊斯", "2019-10-20", "英国");
String result;
//获取一个 罗罗的航空发动机
result = rollsRoyce.getAeroEngine();
System.out.println(result);
//获取一个船舶动力
result = rollsRoyce.getShipPower();
System.out.println(result);
}
}

/**
* 罗尔斯罗伊斯
* <p>
* 产品线有 航空发动机、船舶动力、火车动力、汽车
*
* @author: CYX
* @create: 2019/10/22 11:33
**/
public class RollsRoyce {
/**
* 品牌名称
*/
private String brandName;
/**
* 生产日期(出厂日期)
*/
private String dateManufacture;
/**
* 产地
*/
private String placeOrigin;
/**
* 获取航空发动机
*
* @return
*/
public String getAeroEngine() {
return new AeroEngine().getAeroEngine();
}
/**
* 获取船舶动力
*
* @return
*/
public String getShipPower() {
return new ShipPower().getShipPower();
}
/**
* 航空发动机
*/
class AeroEngine {
public String getAeroEngine() {
StringBuilder sb = new StringBuilder();
sb.append(brandName).append(" / ");
sb.append("民用航空发动机").append(" / ");
sb.append(dateManufacture).append(" / ");
sb.append(placeOrigin);
return sb.toString();
}
}
/**
* 船舶动力
*/
class ShipPower {
public String getShipPower() {
StringBuilder sb = new StringBuilder();
sb.append(brandName).append(" / ");
sb.append("燃气轮机").append(" / ");
sb.append(dateManufacture).append(" / ");
sb.append(placeOrigin);
return sb.toString();
}
}
public RollsRoyce() { }
public RollsRoyce(String brandName, String dateManufacture, String placeOrigin) {
this.brandName = brandName;
this.dateManufacture = dateManufacture;
this.placeOrigin = placeOrigin;
}
// get() set()....
}

1.2. 静态嵌套类

与静态类方法一样,静态嵌套类 不能直接引用其 封闭类 中定义的实例变量或方法:它只能通过对象引用来使用它们。

静态嵌套类 和 其他类的成员交互,就像其他顶级类一样。

静态嵌套类 在行为上是顶级类;在代码层面,只是为了降低包的深度。

1
2
3
4
5
6
7
8
9
class OuterClass {
//...
static class StaticNestedClass {
//...
}
class InnerClass {
//...
}
}

1.2.1. 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
public class AppTest {
public static void main(String[] args) {
String result;
GeneralMotorsCompany.Buick buick = new GeneralMotorsCompany.Buick("黑色","四驱");
result = buick.getBuick();
System.out.println(result);
GeneralMotorsCompany.Chevrolet chevrolet = new GeneralMotorsCompany.Chevrolet("白色", "两驱");
result = chevrolet.getChevrolet();
System.out.println(result);
}
}

/**
* @author: CYX
* @create: 2019-10-22 14:31
**/
public class GeneralMotorsCompany {
/**
* 品牌名称
*/
private String brandName;
/**
* 生产日期(出厂日期)
*/
private String dateManufacture;
/**
* 产地
*/
private String placeOrigin;
/**
* 别克汽车
*/
static class Buick {
/**
* 颜色
*/
private String colour;
/**
* 驱动
*/
private String drive;
public String getBuick() {
final StringBuilder sb = new StringBuilder("Buick{");
sb.append("colour='").append(colour).append('\'');
sb.append(", drive='").append(drive).append('\'');
sb.append('}');
return sb.toString();
}
public Buick() { }
public Buick(String colour, String drive) {
this.colour = colour;
this.drive = drive;
}
// get() set()....
}

/**
* 雪佛兰
*/
static class Chevrolet {
/**
* 颜色
*/
private String colour;
/**
* 驱动
*/
private String drive;
public String getChevrolet() {
final StringBuilder sb = new StringBuilder("Chevrolet{");
sb.append("colour='").append(colour).append('\'');
sb.append(", drive='").append(drive).append('\'');
sb.append('}');
return sb.toString();
}
public Chevrolet() { }
public Chevrolet(String colour, String drive) {
this.colour = colour;
this.drive = drive;
}
// get() set()....
}
}

2. 为什么要使用 内部类

  1. 逻辑分组

    如果 一个类(b),仅对 另一个类(A) 有用,那可以考虑将b嵌入到A中,使得代码更加简洁。

  2. 封装性

    通过将 b类 隐藏在 A类 中,可以将A的成员声明为私有,而b可以访问它们。 另外,b本身可以对外界隐藏

  3. 代码

    代码更具有可读性、可维护性。

    将小类嵌套在顶级类中,使得代码更靠近使用的位置。


3. 注意

Oracle官方文档中,不建议对内部类进行序列化


4. Reference