非静态内部类、局部内部类、匿名内部类为啥能够访问外部类?

137 阅读1分钟

通过class文件可以清楚的知道,这些内部类的构造方法中会自动传入外部类的实例,所以能够访问外部类中的实例。

源码

package com.jwslh.clz;

public class Out {
    interface IOut {
        void i();
    }

     void testOut() {
    }
    
    class Inner {
        public void testInner() {
            IOut out = new IOut() {
                @Override
                public void i() {
                    testOut();
                }
            };
        }
    }

    public static void main(String[] args) {
        Out out = new Out();
    }
}

Out$Inner.class

Compiled from "Out.java"
class com.jwslh.clz.Out$Inner {
  final com.jwslh.clz.Out this$0;

   // 构造方法中会自动传入外部类的实例,所以创建内部类需要在实例中创建
  com.jwslh.clz.Out$Inner(com.jwslh.clz.Out); // 构造方法传入外部类实例
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #1                  // Field this$0:Lcom/jwslh/clz/Out; 赋值
       5: aload_0
       6: invokespecial #2                  // Method java/lang/Object."<init>":()V 调用super
       9: return

  public void testInner();
    Code:
       0: new           #3                  // class com/jwslh/clz/Out$Inner$1
       3: dup
       4: aload_0
       5: invokespecial #4                  // Method com/jwslh/clz/Out$Inner$1."<init>":(Lcom/jwslh/clz/Out$Inner;)V
       8: astore_1
       9: return
}

Out$Inner1.class

Compiled from "Out.java"
class com.jwslh.clz.Out$Inner$1 implements com.jwslh.clz.Out$IOut {
  final com.jwslh.clz.Out$Inner this$1;
  
  com.jwslh.clz.Out$Inner$1(com.jwslh.clz.Out$Inner);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #1                  // Field this$1:Lcom/jwslh/clz/Out$Inner;
       5: aload_0
       6: invokespecial #2                  // Method java/lang/Object."<init>":()V
       9: return

  public void i();
    Code:
       0: aload_0
       1: getfield      #1                  // Field this$1:Lcom/jwslh/clz/Out$Inner;
       4: getfield      #3                  // Field com/jwslh/clz/Out$Inner.this$0:Lcom/jwslh/clz/Out;
       7: invokevirtual #4                  // Method com/jwslh/clz/Out.testOut:()V
      10: return
}

Out.class

Compiled from "Out.java"
public class com.jwslh.clz.Out {
  public com.jwslh.clz.Out();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  void testOut();
    Code:
       0: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class com/jwslh/clz/Out
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_1
       8: return
}