java非静态实名内部类加载顺序问题

之前逛帖子时看到了这么一种说法,外部类先于内部类加载,抱着好奇的心态,尝试了一下反编译,发现并不是如此,内部类比外部类先加载,只是外部类先执行构造方法,接着将this指针传给内部类的构造函数。

实验代码如下:

class deal
{   
    class deal1
    {
    }
}
public class Try {
    public static void main(String[] args) {
         deal.deal1 n=new deal().new deal1(); 
    } 
}
反编译Try.class文件后:

  Last modified 2018-1-29; size 410 bytes
  MD5 checksum 42a56edb44f2c568af2ca2a51a2cb875
  Compiled from "Try.java"
public class Try
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #8.#17         // java/lang/Object."<init>":()V
   #2 = Class              #18            // deal$deal1
   #3 = Class              #21            // deal
   #4 = Methodref          #3.#17         // deal."<init>":()V
   #5 = Methodref          #8.#22         // java/lang/Object.getClass:()Ljava/lang/Class;
   #6 = Methodref          #2.#23         // deal$deal1."<init>":(Ldeal;)V
   #7 = Class              #24            // Try
   #8 = Class              #25            // java/lang/Object
   #9 = Utf8               <init>
  #10 = Utf8               ()V
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               main
  #14 = Utf8               ([Ljava/lang/String;)V
  #15 = Utf8               SourceFile
  #16 = Utf8               Try.java
  #17 = NameAndType        #9:#10         // "<init>":()V
  #18 = Utf8               deal$deal1
  #19 = Utf8               deal1
  #20 = Utf8               InnerClasses
  #21 = Utf8               deal
  #22 = NameAndType        #26:#27        // getClass:()Ljava/lang/Class;
  #23 = NameAndType        #9:#28         // "<init>":(Ldeal;)V
  #24 = Utf8               Try
  #25 = Utf8               java/lang/Object
  #26 = Utf8               getClass
  #27 = Utf8               ()Ljava/lang/Class;
  #28 = Utf8               (Ldeal;)V
{
  public Try();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 7: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=2, args_size=1
         0: new           #2                  // class deal$deal1,可以看到先加载内部类,此时类加载的一套龙服务都会完成。
         3: dup
         4: new           #3                  // class deal,此处加载外部类。
         7: dup
         8: invokespecial #4                  // Method deal."<init>":()V
        11: dup
        12: invokevirtual #5                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
        15: pop
        16: invokespecial #6                  // Method deal$deal1."<init>":(Ldeal;)V
        19: astore_1
        20: return
      LineNumberTable:
        line 9: 0
        line 10: 20
}
SourceFile: "Try.java"
InnerClasses:
     #19= #2 of #3; //deal1=class deal$deal1 of class deal

可以看到,JVM先执行内部类的new指令,该指令会导致内部类被加载,完成一系列加载过程后,会在堆内存中根据方法区的类信息进行内存分配,接着加载和分配内存给外部类,然后执行外部类的<init>方法,最后执行内部类的<init>方法,传入外部类的this指针。

这段反编译代码有些地方不是很懂,中间会调用外部类的getClass方法,但返回值又没有用(调用该函数的下一条指令为pop,返回值没用过就丢弃了),以后在研究。

所以,内部类先于外部类加载。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值