Java:请问这段代码的执行顺序是怎么样的,如果能够详细点更好,谢谢

发布于 2022-09-04 10:30:48 字数 284 浏览 19 评论 0

这是一道关于Java 类的初始化顺序的问题,目前可以懵懂(思维混乱)地知道初始化顺序为 成员变量->构造方法->成员方法 ,静态代码块->构造代码块->构造方法, 但是感觉很混乱,希望能够通过下面这道题理顺一下
图片描述

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

笑饮青盏花 2022-09-11 10:30:48

题主可以通过编译后的class文件反编译来帮助理解初始化过程。

在命令行中的指令javap -l -c -p -v App,执行后就会得到反编译后的内容,下面结合题主给的源码简单分析一下:
下面展示和初始化有关的部分反编译内容
App的class文件

private static com.real.test.App d;
  descriptor: Lcom/real/test/App;
  flags: ACC_PRIVATE, ACC_STATIC

private com.real.test.SubClass t;
  descriptor: Lcom/real/test/SubClass;
  flags: ACC_PRIVATE

static {};
  descriptor: ()V
  flags: ACC_STATIC
  Code:
    stack=2, locals=0, args_size=0
       0: new           #1                  // class com/real/test/App
       3: dup
       4: invokespecial #12                 // Method "<init>":()V  **调用App的构造函数**
       7: putstatic     #15                 // Field d:Lcom/real/test/App;
      10: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
      13: iconst_3   **得到数字常量3**
      14: invokevirtual #23                 // Method java/io/PrintStream.println:(I)V   **打印数字常量3**
      17: return
    LineNumberTable:
      line 4: 0
      line 8: 10
      line 3: 17
    LocalVariableTable:
      Start  Length  Slot  Name   Signature

com.real.test.App();   **构造函数详细内容**
  descriptor: ()V
  flags:
  Code:
    stack=3, locals=1, args_size=1
       0: aload_0
       1: invokespecial #31                 // Method java/lang/Object."<init>":()V   **调用Object的构造函数**
       4: aload_0
       5: new           #32                 // class com/real/test/SubClass
       8: dup
       9: invokespecial #34                 // Method com/real/test/SubClass."<init>":()V   **调用SubClass的构造函数**
      12: putfield      #35                 // Field t:Lcom/real/test/SubClass;
      15: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
      18: iconst_4   **得到数字常量4**
      19: invokevirtual #23                 // Method java/io/PrintStream.println:(I)V   **打印数字常量4**
      22: return
    LineNumberTable:
      line 11: 0
      line 5: 4
      line 12: 15
      line 13: 22
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      23     0  this   Lcom/real/test/App;

public static void main(java.lang.String[]);
  descriptor: ([Ljava/lang/String;)V
  flags: ACC_PUBLIC, ACC_STATIC
  Code:
    stack=2, locals=1, args_size=1
       0: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #40                 // String Hello  **得到字符串Hello**
       5: invokevirtual #42                 // Method java/io/PrintStream.println:(Ljava/lang/String   **打印字符串**
       8: return
    LineNumberTable:
      line 16: 0
      line 17: 8
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       9     0  args   [Ljava/lang/String;

SubClass的class文件

static {};  **静态块**
  descriptor: ()V
  flags: ACC_STATIC
  Code:
    stack=2, locals=0, args_size=0
       0: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: iconst_1   **得到数字常量1**
       4: invokevirtual #14                 // Method java/io/PrintStream.println:(I)V   **打印数字常量1**
       7: return
    LineNumberTable:
      line 28: 0
      line 26: 7
    LocalVariableTable:
      Start  Length  Slot  Name   Signature

public com.real.test.SubClass();  **构造函数**
  descriptor: ()V
  flags: ACC_PUBLIC
  Code:
    stack=2, locals=1, args_size=1
       0: aload_0
       1: invokespecial #23                 // Method com/real/test/SuperClass."<init>":()V   **调用SuperClass的构造函数**
       4: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
       7: iconst_2   **得到数字常量2**
       8: invokevirtual #14                 // Method java/io/PrintStream.println:(I)V   **打印数字常量2**
      11: return
    LineNumberTable:
      line 31: 0
      line 32: 4
      line 33: 11
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      12     0  this   Lcom/real/test/SubClass;

SuperClass的class文件

 com.real.test.SuperClass();
   descriptor: ()V
   flags:
   Code:
     stack=2, locals=1, args_size=1
        0: aload_0
        1: invokespecial #8                  // Method java/lang/Object."<init>":()V   **Object的构造函数**
        4: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
        7: ldc           #16                 // String 构造SuperClass   **得到字符串构造SuperClass**
        9: invokevirtual #18                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V   **打印字符串**
       12: return
     LineNumberTable:
       line 21: 0
       line 22: 4
       line 23: 12
     LocalVariableTable:
       Start  Length  Slot  Name   Signature
           0      13     0  this   Lcom/real/test/SuperClass;

大致解释一下内容(如果题主对JVM指令集感兴趣可以看看JVM规范,里面有很详细的解释)。
上面反编译内容中星号部分是我加上的注解。按照代码的执行顺序:
1.JVM加载App类,App中的静态变量在这时会初始化,对应App中调用App的构造函数的字节码
2.跳到App的构造函数,先初始化父类Object,对应App中调用Object的构造函数
3.初始化实例变量SubClass,对应App中调用SubClass的构造函数
4.此时要先加载SubClass类,同时初始化静态变量并执行静态块,对应SubClass中静态块
5.这时执行SubClass中的代码打印出“1”
6.SubClass加载完成后执行构造函数,对应SubClass中构造函数
7.SubClass构造函数最开始是执行SuperClass的构造函数,对应SubClass中调用SuperClass的构造函数
8.执行SuperClass中构造函数中的代码打印出“得到字符串构造SuperClass”
9.SuperClass构造完成return到7中的代码位置,继续执行SubClass剩余的代码
10.执行SubClass中构造函数代码打印出“2”
11.执行完SubClass构造函数return到3中的代码位置,继续执行App剩余的代码
12.执行App中构造函数代码打印出“4”
13.执行完App的构造函数return到1中代码位置,继续初始化的静态变量
14.执行静态块中的方法,答应出“3”
15.进入到main入口方法,打印出“Hello”

上面的过程就是大致的执行顺序。

回答的内容可能会有点混乱,题主看不懂的地方可以问我。

八巷 2022-09-11 10:30:48

类变量(静态变量)>静态块>构造方法>普通成员变量>子类除静态外。JAVA所有static修饰的都会在编译时分配空间,而对象只会在使用时才分配即new的时候,子类继承父类很明显需要先给父类分配,没有父亲哪来的儿子是吧

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文