Java 内部类持有外部类的引用

常用命令

编译:javac Demo.java 生成 class 文件

查看外部类字节码:javap -c -p OuterClass.class

查看内部类字节码:javap -c -p OuterClass$InnerClass.class

源码

class OuterClass {

    private int privateField = 10;

    private void privateMethod() {
        System.out.println("这是一个私有方法");
    }

    class InnerClass {
        public void accessOuter() {
            System.out.println(privateField);
            privateMethod();
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        OuterClass.InnerClass inner = outer.new InnerClass();
        inner.accessOuter();
    }
}

字节码

执行 javac Demo.java 生成3个文件:

  • Demo.class
  • OuterClass.class:外部类的class文件
  • OuterClass$InnerClass.class:内部类的class文件

执行 javap -c -p OuterClass.class 输出字节码:

Compiled from "Demo.java"
class com.test.lib_java.OuterClass {
  private int privateField;

  com.test.lib_java.OuterClass();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: bipush        10
       7: putfield      #7                  // Field privateField:I
      10: return

  private void privateMethod();
    Code:
       0: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #19                 // String privateMethod
       5: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

执行 javap -c -p 'OuterClass$InnerClass.class' 输出字节码:

Compiled from "Demo.java"
class com.test.lib_java.OuterClass$InnerClass {
  final com.test.lib_java.OuterClass this$0; // 持有外部类的引用

  // 构造函数接收外部类的引用
  com.test.lib_java.OuterClass$InnerClass(com.test.lib_java.OuterClass);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #1                  // Field this$0:Lcom/test/lib_java/OuterClass;
       5: aload_0
       6: invokespecial #7                  // Method java/lang/Object."<init>":()V
       9: return

  public void accessOuter();
    Code:
       0: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_0
       4: getfield      #1                  // Field this$0:Lcom/test/lib_java/OuterClass;
       7: getfield      #19                 // Field com/test/lib_java/OuterClass.privateField:I
      10: invokevirtual #25                 // Method java/io/PrintStream.println:(I)V
      13: aload_0
      14: getfield      #1                  // Field this$0:Lcom/test/lib_java/OuterClass;
      17: invokevirtual #31                 // Method com/test/lib_java/OuterClass.privateMethod:()V
      20: return
}

说明在编译器:

  • 有多少个类生成多少个 .class 文件

  • 内部类的类名变为 外部类名$内部类名 的形式

  • 内部类中持有一个 final 类型的外部类引用,通常命名为 this$0

  • 内部类的构造函数被修改了,外部类实例作为参数传入

  • 内部类直接访问外部类私有字段:

    7: getfield      #19                 // Field com/test/lib_java/OuterClass.privateField:I
    
  • 内部类直接访问外部类私有方法:

    17: invokevirtual #31                 // Method com/test/lib_java/OuterClass.privateMethod:()V
    
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐