1. 概要

JVMは、2つの異なるメソッドを使用して、オブジェクトインスタンスとクラスを初期化します。

このクイック記事では、コンパイラとランタイムがどのようにと初期化を目的としたメソッド。

2. インスタンスの初期化メソッド

簡単なオブジェクトの割り当てと割り当てから始めましょう。

Object obj = new Object();

このスニペットをコンパイルし、 javap -c を介してそのバイトコードを見ると、次のようになります。

0: new           #2      // class java/lang/Object
3: dup
4: invokespecial #1      // Method java/lang/Object."<init>":()V
7: astore_1

オブジェクトを初期化するには JVMは、という名前の特別なメソッドを呼び出します 。  JVMの専門用語では、このメソッドはインスタンスの初期化メソッドです。 。 メソッドは、次の場合にのみインスタンスの初期化になります。

  • クラスで定義されています
  • その名前は < init>
  • voidを返します

各クラスは0個以上のインスタンス初期化メソッドを持つことができます。 これらのメソッドは通常、JavaやKotlinなどのJVMベースのプログラミング言語のコンストラクターに対応しています。

2.1. コンストラクターとインスタンス初期化ブロック

Javaコンパイラがコンストラクタを次のように変換する方法をよりよく理解するため 、別の例を考えてみましょう:

public class Person {
    
    private String firstName = "Foo"; // <init>
    private String lastName = "Bar"; // <init>
    
    // <init>
    {
        System.out.println("Initializing...");
    }

    // <init>
    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    
    // <init>
    public Person() {
    }
}

これは、このクラスのバイトコードです。

public Person(java.lang.String, java.lang.String);
  Code:
     0: aload_0
     1: invokespecial #1       // Method java/lang/Object."<init>":()V
     4: aload_0
     5: ldc           #7       // String Foo
     7: putfield      #9       // Field firstName:Ljava/lang/String;
    10: aload_0
    11: ldc           #15      // String Bar
    13: putfield      #17      // Field lastName:Ljava/lang/String;
    16: getstatic     #20      // Field java/lang/System.out:Ljava/io/PrintStream;
    19: ldc           #26      // String Initializing...
    21: invokevirtual #28      // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    24: aload_0
    25: aload_1
    26: putfield      #9       // Field firstName:Ljava/lang/String;
    29: aload_0
    30: aload_2
    31: putfield      #17      // Field lastName:Ljava/lang/String;
    34: return

Javaではコンストラクターブロックとイニシャライザーブロックは分離されていますが、バイトコードレベルでは同じインスタンス初期化メソッドにあります。 実際のところ、これは方法:

  • まず、firstNameおよびlastNameフィールドを初期化します(インデックス0から13)
  • 次に、インスタンス初期化ブロック(インデックス16から21)の一部としてコンソールに何かを出力します。
  • そして最後に、コンストラクター引数でインスタンス変数を更新します

次のようにPersonを作成する場合:

Person person = new Person("Brian", "Goetz");

次に、これは次のバイトコードに変換されます。

0: new           #7        // class Person
3: dup
4: ldc           #9        // String Brian
6: ldc           #11       // String Goetz
8: invokespecial #13       // Method Person."<init>":(Ljava/lang/String;Ljava/lang/String;)V
11: astore_1

今回、JVMは別の Javaコンストラクターに対応する署名を持つメソッド。

ここで重要なポイントは、コンストラクターと他のインスタンス初期化子が JVMの世界でのメソッド。

3. クラス初期化メソッド

Javaでは、静的初期化ブロックは、クラスレベルで何かを初期化する場合に役立ちます。

public class Person {

    private static final Logger LOGGER = LoggerFactory.getLogger(Person.class); // <clinit>

    // <clinit>
    static {
        System.out.println("Static Initializing...");
    }

    // omitted
}

上記のコードをコンパイルすると、コンパイラは静的ブロックをバイトコードレベルでクラス初期化メソッドに変換します。

簡単に言うと、メソッドは、次の場合にのみクラスの初期化になります。

  • その名前は
  • voidを返します

したがって、を生成する唯一の方法は Javaのメソッドは、静的フィールドと静的ブロック初期化子を使用することです。

JVMは初めて対応するクラスを使用します。 したがって、 呼び出しは実行時に発生し、バイトコードレベルでの呼び出しを確認することはできません。

4. 結論

この簡単な記事では、 と JVMのメソッド。 The メソッドは、オブジェクトインスタンスを初期化するために使用されます。  また、JVMは必要に応じてクラスを初期化するメソッド。

JVMで初期化がどのように機能するかをよりよく理解するには、JVM仕様を読むことを強くお勧めします。