定义在一个类内部的类,称为内部类(累不累),如下:
- public class A {
- private int c = 1;
- public class C {
- public void test() {
- System.out.println("c:" + c);
- }
- }
- }
C 称为 A 的内部类,简称内部类
A 称为 C 的外部类,简称外部类
而且内部类能访问外部类的成员(静态成员、实例成员),当然有一些限制,限制如下
按照内部类的声明方式,分为 4 种内部类:
静态内部类,只能访问外部类的静态成员(方法和变量),并且可以像类的成员一样使用修饰符(public/protected/private); 创建静态内部类对象的方式:
- public class A {
- private static String b = "b";
- private int c = 1;
- // B是A的静态内部类
- public static class B {
- public void test() {
- System.out.println(b);
- }
- }
- }
;
- A.B b = new A.B()
成员内部类,访问外部类的一切(静态,还是实例), 就像成员方法一样, 并且可以像类的成员一样使用修饰符(public/protected/private) 创建成员内部类对象的方式:
- public class A {
- private static String b = "b";
- private int c = 1;
- // C是A的成员内部类
- public class C {
- public void test() {
- System.out.println(c);
- System.out.println(b);
- }
- }
- }
- A a = new A();
- A.C c = a.new C();
方法内部类,和它所在的方法(代码块),具有相同的访问能力,如果上面代码是在 static 方法中声明的,那么内部类 D 不能访问 c 变量。 jdk1.8 方法内部类,能够访问非 final 类型的局部变量,本质相当有在内部类 D 内保存了副本
- public class A {
- private static String b;
- private int c;
- // 成员方法
- public void test() {
- final int d = 1;
- // 方法内部类
- class D {
- public void test() {
- // 访问静态变量
- System.out.println(b);
- // 访问实例变量
- System.out.println(c);
- // 访问方法final类型的局部变量
- System.out.println(d);
- }
- }
- }
- }
内部类的语法颇为奇怪,我们来看看如下代码,编译后的字节码文件!
- public class A {
- private static String b = "b";
- private int c = 1;
- // 静态内部类
- public static class B {
- public void b() {
- System.out.println(b);
- }
- }
- // 成员内部类
- class C {
- public void c() {
- System.out.println(c);
- }
- }
- }
内部类会被编译成单独的 class 文件,那意味 JVM 解释执行 class 文件时类 "B" 和类 A 是独立的,由此可以见内部类也是一种语法糖!
对于 JVM 来说,类 A 的 private b 和 c 成员,怎么能分别被类 B 和类 C 访问到的了!
用 javap 命令反编译类 A.class 来看看:
秘密就来自,编译器为外部类生的两个静态访问方法,
返回 b 变量的值,
- Stinrg access$000()
返回 a 对象的 c 成员变量值;
- int access$100(A a)
而在静态内部类 B 中,编译器将访问静态变量 b 的地方替换为如上方法:
- // 静态内部类
- public static class A$B {
- public void b() {
- System.out.println(A.access$000());
- }
- }
在成员内部类 C 中,原理也是如此,不过增加了更多的东西,反编译 A$C.class:
;
- final A $this
- System.out.println(A.access$100($this));
你一定会好奇成员构造方法中的外部类对象的参数从哪里传入的!看看我们是怎么声明内部类的对象的
- A a = new A();
- A.C c = a.new C();
将会被编译器替换成:
- A a = new A();
- A$C c = new A$C(a);
两个类之间紧密联系时,可以使用内部类:
来源: http://www.cnblogs.com/luokaiqiongmou/p/6483112.html