java内部类

253 阅读2分钟

静态内部类

public class Anonymous {
    static String a = "sss";
    void fun(){
        new Inner().fun();
    }


    static class  Inner {
        void fun () {
            System.out.println(a);
        }
    }
}

使用javac Anonymous可以得到Anonymous.classAnonymous$Inner.class两个字class文件

在IDE中反编译class文件:

Anonymous.class:
public class Anonymous {
    static String a = "sss";

    public Anonymous() {
    }

    void fun() {
        (new Anonymous.Inner()).fun();
    }

    static class Inner {
        Inner() {
        }

        void fun() {
            System.out.println(Anonymous.a);
        }
    }
}
Anonymous$Inner.class:
class Anonymous$Inner {
    Anonymous$Inner() {
    }

    void fun() {
        System.out.println(Anonymous.a);
    }
}
字节码javap -c Anonymous
public class main.com.example.train.Anonymous {
  static java.lang.String a;

  public main.com.example.train.Anonymous();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  void fun();
    Code:
       0: new           #2                  // class main/com/example/train/Anonymous$Inner
       3: dup
       4: invokespecial #3                  // Method main/com/example/train/Anonymous$Inner."<init>":()V
       7: invokevirtual #4                  // Method main/com/example/train/Anonymous$Inner.fun:()V
      10: return

  static {};
    Code:
       0: ldc           #5                  // String sss
       2: putstatic     #6                  // Field a:Ljava/lang/String;
       5: return
}

字节码javap -c Anonymous$Inner

class main.com.example.train.Anonymous$Inner {
  main.com.example.train.Anonymous$Inner();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  void fun();
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: getstatic     #3                  // Field main/com/example/train/Anonymous.a:Ljava/lang/String;
       6: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       9: return
}
结论:
  1. 静态内部类会编译成一个新类
  2. 静态内部类直接访问外部类的静态变量(getstatic指令)

成员内部类

public class Anonymous {
    private String a ;
    void fun(){
        new Inner().fun();
    }


    class  Inner {
        void fun () {
            System.out.println(a);
        }
    }
}
Anonymous$Inner.class:
class Anonymous$Inner {
    Anonymous$Inner(Anonymous var1) {
        this.this$0 = var1;
    }

    void fun() {
        System.out.println(this.this$0.a);
    }
}

字节码:

public class main.com.example.train.Anonymous {
  public main.com.example.train.Anonymous();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  void fun();
    Code:
       0: new           #2                  // class main/com/example/train/Anonymous$Inner
       3: dup
       4: aload_0
       5: invokespecial #3                  // Method main/com/example/train/Anonymous$Inner."<init>":(Lmain/com/example/train/Anonymous;)V
       8: invokevirtual #4                  // Method main/com/example/train/Anonymous$Inner.fun:()V
      11: return
}
class Anonymous$Inner {
    Anonymous$Inner(Anonymous var1) {
        this.this$0 = var1;
    }

    void fun() {
        System.out.println(this.this$0.a);
    }
}
结论:
  1. 局部内部类也是编译成一个新类

  2. 局部内部类的构造方法的参数包含外部类

  3. new一个局部内部类时会传入外部类对象的引用

    (aload_0 is supposed to push 'this' on to the stack)

  4. 内部类访问外部类的变量是通过传入的外部类对象进行访问

局部类

方法中的类即为局部类

public class Anonymous {
    private String a;

    void fun() {
        class Inner {
            void fun() {
                System.out.println(a);
            }
        }
        new Inner().fun();
    }
}

Anonymous$1Inner

class Anonymous$1Inner {
    Anonymous$1Inner(Anonymous var1) {
        this.this$0 = var1;
    }

    void fun() {
        System.out.println(this.this$0.a);
    }
}

字节码:

public class main.com.example.train.Anonymous {
  public main.com.example.train.Anonymous();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  void fun();
    Code:
       0: new           #2                  // class main/com/example/train/Anonymous$1Inner
       3: dup
       4: aload_0
       5: invokespecial #3                  // Method main/com/example/train/Anonymous$1Inner."<init>":(Lmain/com/example/train/Anonymous;)V
       8: invokevirtual #4                  // Method main/com/example/train/Anonymous$1Inner.fun:()V
      11: return
}

和成员内部类相似。

匿名内部类

没有名字的内部类。。

public class Anonymous {
    private String a;

    void fun() {
        Inner inner = new Inner() {
            @Override
            public void fun() {

            }
        };
        inner.fun();
    }

    interface Inner {
        void fun();
    }
}

Anonymous$1.class :

class Anonymous$1 implements Inner {
    Anonymous$1(Anonymous var1) {
        this.this$0 = var1;
    }

    public void fun() {
    }
}

字节码:

public class main.com.example.train.Anonymous {
  public main.com.example.train.Anonymous();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  void fun();
    Code:
       0: new           #2                  // class main/com/example/train/Anonymous$1
       3: dup
       4: aload_0
       5: invokespecial #3                  // Method main/com/example/train/Anonymous$1."<init>":(Lmain/com/example/train/Anonymous;)V
       8: astore_1
       9: aload_1
      10: invokeinterface #4,  1            // InterfaceMethod main/com/example/train/Anonymous$Inner.fun:()V
      15: return
}

与局部内部类相似,匿名内部类的构造方法需要外部类对象作为参数,然后,匿名内部类通过这个对象访问外部类的变量和方法。