内部类:是指在类的内部又定义了一个类。根据位置的不同可以分为成员内部类和局部内部类。
成员内部类
在成员变量的位置定义一个类。
1. 依赖外部类对象存在
2. 可以访问外部类的成员变量和成员方法。
访问方式:
1. 直接访问,直接使用变量名和方法名
2. 通过外部类名.this.变量名/方法名
package test;
public class Outer {
private int num = 1;
public void before() {
System.out.println("before");
}
// 成员变量,成员方法,成员内部类是一样
public class Inner{
private int count = 2;
private int num = 2;
public void speak() {
System.out.println(num); // 2
System.out.println(Outer.this.num); // 1
before(); // before
System.out.println(count); // 2
}
public Inner() {
super();
}
}
}
编译生成Outer.class和Outer$Inner.class两个class文件
用javap -c Outer$Inner.class 命令反编译查看
public class test.Outer$Inner {
final test.Outer this$0;
public void speak();
Code:
0: getstatic #13 // Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_0
4: getfield #19 // Field num:I
7: invokevirtual #21 // Method java/io/PrintStream.println:(I)V
10: getstatic #13 // Field java/lang/System.out:Ljava/io/PrintStream;
13: aload_0
14: getfield #27 // Field this$0:Ltest/Outer;
17: invokestatic #29 // Method test/Outer.access$0:(Ltest/Outer;)I
20: invokevirtual #21 // Method java/io/PrintStream.println:(I)V
23: aload_0
24: getfield #27 // Field this$0:Ltest/Outer;
27: invokevirtual #35 // Method test/Outer.before:()V
30: getstatic #13 // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_0
34: getfield #38 // Field count:I
37: invokevirtual #21 // Method java/io/PrintStream.println:(I)V
40: return
public test.Outer$Inner(test.Outer);
Code:
0: aload_0
1: aload_1
2: putfield #27 // Field this$0:Ltest/Outer;
5: aload_0
6: invokespecial #46 // Method java/lang/Object."<init>":()V
9: aload_0
10: iconst_2
11: putfield #38 // Field count:I
14: aload_0
15: iconst_2
16: putfield #19 // Field num:I
19: return
}
在编译成class文件的过程,编译器会自己在Inner类中生成一个指向父类对象的引用,并且只含一个有外部类类型的参数的构造方法。
所以看到这就明白了为何内部类能访问外部类对象的成员变量和方法,并且依赖外部类对象存在。
静态成员内部类
在成员内部类的基础上加上了static关键字修饰
1.不依赖外部类对象存在
2.只能访问外部类的静态成员变量和静态方法。
访问方式:
1. 直接访问,直接使用变量名和方法名
2. 通过外部类名.变量名/方法名
package test;
public class Outer {
private static int num = 1;
public void before() {
System.out.println("before");
}
// 静态成员内部类
public static class Inner{
private int count = 2;
private int num = 2;
public void speak() {
System.out.println(num); // 2
System.out.println(Outer.num); // 通过类名的方式访问
System.out.println(count); // 2
}
public Inner() {
super();
}
}
}
创建内部类对象: Outer.Inner inner = new Outer().new Inner();
编译生成Outer.class和Outer$Inner.class两个class文件
用javap -c Outer$Inner.class 命令反编译查看
public class test.Outer$Inner {
public void speak();
Code:
0: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_0
4: getfield #17 // Field num:I
7: invokevirtual #19 // Method java/io/PrintStream.println:(I)V
10: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream;
13: invokestatic #25 // Method test/Outer.access$0:()I
16: invokevirtual #19 // Method java/io/PrintStream.println:(I)V
19: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream;
22: aload_0
23: getfield #31 // Field count:I
26: invokevirtual #19 // Method java/io/PrintStream.println:(I)V
29: return
public test.Outer$Inner();
Code:
0: aload_0
1: invokespecial #38 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_2
6: putfield #31 // Field count:I
9: aload_0
10: iconst_2
11: putfield #17 // Field num:I
14: return
}
发现静态成员内部类没有外部类对象的引用,所以不能访问外部类对象的非静态的成员变量和方法。它是相当一个独立的类,但限制了访问方式,要通过外部类访问内部类。此时内部类相当于外部类的静态成员.
创建内部类对象:Outer.Inner inner = new Outer.Inner();
成员内部类
在方法中声明的一个类
package test;
public class Outer2 {
private int num = 1;
public void print() {
System.out.println("Outer的print");
}
public void fun() {
// 局部内部类
class Inner{
public void print() {
System.out.println("Inner的print");
}
public void test() {
Outer2.this.print(); // 调用外部类对象的方法
}
}
new Inner().print();
new Inner().test();
}
public static void main(String[] args) {
Outer2 outer2 = new Outer2();
outer2.fun();
}
}
运行结果如下
Inner的print
Outer的print
打开反编译工具查看下代码
class test.Outer2$1Inner {
final test.Outer2 this$0;
test.Outer2$1Inner(test.Outer2);
Code:
0: aload_0
1: aload_1
2: putfield #10 // Field this$0:Ltest/Outer2;
5: aload_0
6: invokespecial #12 // Method java/lang/Object."<init>":()V
9: return
public void print();
Code:
0: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #26 // String Inner的print
5: invokevirtual #28 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
public void test();
Code:
0: aload_0
1: getfield #10 // Field this$0:Ltest/Outer2;
4: invokevirtual #35 // Method test/Outer2.print:()V
7: return
}
同样局部内部类含有外部类对象的引用并且有且仅有一个含有外部类类型的参数的构造方法,和成员内部类是一样的。
和成员内部类的区别就是,成员内部类对象可以在其他的类中创建,而局部内部类只能在方法声明并创建,作用域在一个方法中。