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); } }
public class RollsRoyce {
private String brandName;
private String dateManufacture;
private String placeOrigin;
public String getAeroEngine() { return new AeroEngine().getAeroEngine(); }
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; } }
|
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); } }
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; } }
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; } } }
|
2. 为什么要使用 内部类
逻辑分组
如果 一个类(b),仅对 另一个类(A) 有用,那可以考虑将b嵌入到A中,使得代码更加简洁。
封装性
通过将 b类 隐藏在 A类 中,可以将A的成员声明为私有,而b可以访问它们。 另外,b本身可以对外界隐藏
代码
代码更具有可读性、可维护性。
将小类嵌套在顶级类中,使得代码更靠近使用的位置。
3. 注意
Oracle官方文档中,不建议对内部类进行序列化
4. Reference