Java >> Java チュートリアル >  >> JVM

JVM の <init> および <clinit> メソッド

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 を返します

各クラスはゼロ個以上のインスタンス初期化メソッドを持つことができます .これらのメソッドは通常、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 を初期化します および フィールド (インデックス 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 のメソッド。 メソッドは、オブジェクト インスタンスを初期化するために使用されます。また、JVM は を呼び出します 必要に応じてクラスを初期化するメソッド

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


Java タグ