Java中内部类是如何调用外部类的成员变量和方法的?我们下看看下面的例子
package com.iworktool.libjava;
public class Outer{
private String privateValue = "privateValue";
public String publicValue = "publicValue";
private class Inner{
public Inner()
{}
public void innerPrint()
{
privatePrint();
System.out.println(privateValue);
publicPrint();
}
}
public Outer()
{
Inner inner = new Inner();
inner.innerPrint();
}
private void privatePrint()
{
System.out.println(privateValue);
}
public void publicPrint()
{
System.out.println(publicValue);
}
}
用javap反编译Outer类生成的class文件
public class com.iworktool.libjava.Outer {
private java.lang.String privateValue;
public java.lang.String publicValue;
public com.iworktool.libjava.Outer();
Code:
0: aload_0
1: invokespecial #3 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #4 // String privateValue
7: putfield #1 // Field privateValue:Ljava/lang/String;
10: aload_0
11: ldc #5 // String publicValue
13: putfield #6 // Field publicValue:Ljava/lang/String;
16: new #7 // class com/iworktool/libjava/Outer$Inner
19: dup
20: aload_0
21: aconst_null
22: invokespecial #8 // Method com/iworktool/libjava/Outer$Inner."<init>":(Lcom/iworktool/libjava/Outer;Lcom/iworktool/libjava/Outer$1;)V
25: astore_1
26: aload_1
27: invokevirtual #9 // Method com/iworktool/libjava/Outer$Inner.innerPrint:()V
30: return
private void print();
Code:
0: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_0
4: getfield #1 // Field privateValue:Ljava/lang/String;
7: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
10: return
public void publicPrint();
Code:
0: return
static void access$000(com.iworktool.libjava.Outer);
Code:
0: aload_0
1: invokespecial #2 // Method print:()V
4: return
static java.lang.String access$100(com.iworktool.libjava.Outer);
Code:
0: aload_0
1: getfield #1 // Field privateValue:Ljava/lang/String;
4: areturn
}
可以看出系统为我们新增加了Default静态方法static void access$000和Default静态成员变量java.lang.String access$100
这两个分别对应了Outer类的私有方法privatePrint和私有成员变量privateValue,通过这种代理的方式就可以让内部类对象能访问到外部类的私有成员和方法
在看看Inner类反编译后的情况
class com.iworktool.libjava.Outer$Inner {
final com.iworktool.libjava.Outer this$0;
public com.iworktool.libjava.Outer$Inner(com.iworktool.libjava.Outer);
Code:
0: aload_0
1: aload_1
2: putfield #1 // Field this$0:Lcom/iworktool/libjava/Outer;
5: aload_0
6: invokespecial #2 // Method java/lang/Object."<init>":()V
9: return
public void innerPrint();
Code:
0: aload_0
1: getfield #1 // Field this$0:Lcom/iworktool/libjava/Outer;
4: invokestatic #3 // Method com/iworktool/libjava/Outer.access$000:(Lcom/iworktool/libjava/Outer;)V
7: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
10: aload_0
11: getfield #1 // Field this$0:Lcom/iworktool/libjava/Outer;
14: invokestatic #5 // Method com/iworktool/libjava/Outer.access$100:(Lcom/iworktool/libjava/Outer;)Ljava/lang/String;
17: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: aload_0
21: getfield #1 // Field this$0:Lcom/iworktool/libjava/Outer;
24: invokevirtual #7 // Method com/iworktool/libjava/Outer.publicPrint:()V
27: return
}
可以看出,系统主动给我们的内部类增加了一个类型为外部类的成员变量 final com.iworktool.libjava.Outer this$0; 并且新增了一个带参构造函数public com.iworktool.libjava.Outer$Inner(com.iworktool.libjava.Outer);在外部类创建内部类对象的时候,会默认把外部类对象传入,这样就可以在内部类中访问外部类对象的成员变量和方法。
在反编译后的代码中有下面几个字节码
invokeinterface 调用接口方法
invokevirtual 调用类的public方法
invokestatic 调用类的静态方法
invokespecial 调用类的私有方法,构造函数