java-se - Java:请问这段代码的执行顺序是怎么样的,如果能够详细点更好,谢谢
PHPz
PHPz 2017-04-18 10:36:29
0
2
391
PHPz
PHPz

学习是最好的投资!

全員に返信(2)
小葫芦

クラス変数 (静的変数) > 静的ブロック > コンストラクター > 静的以外のサブクラスJAVA のすべての静的変更はコンパイル時にスペースを割り当てます。オブジェクトは使用時のみ割り当てられます。つまり、new が使用されるとき、サブクラスが親クラスを継承するときは、明らかに最初に親クラスに割り当てる必要があります。父親がいなくても息子は生まれますよね?

いいねを押す +0
迷茫

この主題は、コンパイルされた class ファイルを逆コンパイルすることで、初期化プロセスを理解するのに役立ちます。 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

コマンドラインの javap -l -c -p -v App コマンドは、実行後に逆コンパイルされたコンテンツを取得します。質問者が提供したソース コードに基づいて簡単に分析してみましょう。
以下は、初期化
アプリ のクラス ファイルに関連する逆コンパイルされたコンテンツの一部を示しています

リーリー

SubClass のクラス ファイル

リーリー

SuperClass のクラス ファイル🎜 リーリー 🎜内容を大まかに説明します (対象者が JVM 命令セット に興味がある場合は、JVM 仕様を読むことができます。これには非常に詳細な説明があります)。
上記の逆コンパイルされた内容のアスタリスク部分は、私が追加した注釈です。コードの実行順序に従います。
1. JVM は App クラスをロードします。App 内の静的変数は、 で App を呼び出します。コンストラクターのバイトコード
2. App のコンストラクターにジャンプし、最初に親クラス Object を初期化して呼び出します。アプリ コンストラクターの に対応するオブジェクト
3. インスタンス変数 SubClass を初期化します。これは、アプリ内のサブクラスのコンストラクターの呼び出し4. このとき、最初に SubClass クラスをロードし、静的変数を初期化し、同時にサブクラスの static ブロック
に対応する静的ブロックを実行する必要があります。 5. このとき、SubClass Out "1" でコードを実行します。
6. SubClass がロードされた後、constructor
7.SubClass の構築 この関数は、SuperClass のコンストラクターを実行することで開始されます。これは、コンストラクターの呼び出しに相当します。サブクラス内のスーパークラスの
8. SuperClass でコンストラクターを実行します。コードは「文字列構築 SuperClass の取得」を出力します。
9.SuperClass 構築は次のとおりです。 completedreturn 7 のコード位置に戻り、SubClass の実行を続行します。
残りのコード
10. SubClass のコンストラクター コードを実行して出力します。 out "2"
11. SubClass コンストラクターの実行を終了します return code> 3 のコード位置に移動し、App の残りのコードの実行を続けます。 code>
12. App でコンストラクター コードを実行し、「4」を出力します。
13. App のコンストラクターを実行した後、return code> を 1 のコード位置に入力し、静的変数の初期化を続けます。
14. 静的ブロック内のメソッドを実行し、「3」を許可します。15. main エントリ メソッドを入力します。 「こんにちは」を印刷してください🎜 🎜上記の処理が大まかな実行シーケンスです。 🎜 🎜回答の内容が少しわかりにくいかもしれませんが、分からないことがあれば質問してください。 🎜
いいねを押す +0
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート