1. 概要

このクイックチュートリアルでは、Javaのコンストラクターの戻り型に焦点を当てます。

まず、JavaとJVMでオブジェクトの初期化がどのように機能するかを理解します。 次に、オブジェクトの初期化と割り当てが内部でどのように機能するかを詳しく調べます。

2. インスタンスの初期化

空のクラスから始めましょう:

public class Color {}

ここでは、このクラスからインスタンスを作成し、それを変数に割り当てます。

Color color = new Color();

この単純なJavaスニペットをコンパイルした後、 java p-cコマンドを使用してそのバイトコードを確認してみましょう。

0: new           #7                  // class Color
3: dup
4: invokespecial #9                  // Method Color."<init>":()V
7: astore_1

Javaでオブジェクトをインスタンス化すると、JVMは次の操作を実行します。

  1. まず、は、新しいオブジェクトのプロセススペースで場所を見つけます。
  2. 次に、JVMはシステム初期化プロセスを実行します。 このステップでは、オブジェクトをデフォルトの状態で作成します。 バイトコード内の新しいオペコードが実際にこのステップを担当します。
  3. 最後に、コンストラクターおよびその他の初期化ブロックを使用してオブジェクトを初期化します。 この場合、 invokespecialopcodeはコンストラクターを呼び出します。

上に示したように、デフォルトのコンストラクターのメソッドシグネチャは次のとおりです。

Method Color."<init>":()V

The JVMのインスタンス初期化メソッドの名前です 。 この場合、 次のような関数です。

  • 入力として何も取りません(メソッド名の後の空の括弧)
  • 何も返しません(Vvoid の略です)

したがって、JavaおよびJVMでのコンストラクターの戻りタイプはvoidです。

簡単な割り当てをもう一度見てみましょう。

Color color = new Color();

コンストラクターがvoidを返すことがわかったので、割り当てがどのように機能するかを見てみましょう。

3. 割り当てのしくみ

JVMはスタックベースの仮想マシンです。 各スタックは、スタックフレームで構成されます。 簡単に言えば、各スタックフレームはメソッド呼び出しに対応します。 実際、JVMは新しいメソッド呼び出しでフレームを作成し、ジョブが完了するとフレームを破棄します。

各スタックフレームは、配列を使用してローカル変数を格納し、オペランドスタックを使用して部分的な結果を格納します。 それを踏まえて、バイトコードをもう一度見てみましょう。

0: new           #7                // class Color
3: dup
4: invokespecial #9               // Method Color."<init>":()V
7: astore_1

割り当ての仕組みは次のとおりです。

  • new 命令は、 Color のインスタンスを作成し、その参照をオペランドスタックにプッシュします。
  • dup オペコードは、オペランドスタックの最後の項目を複製します
  • invokespecial は、複製された参照を取得し、初期化のためにそれを消費します。 この後、元の参照のみがオペランドスタックに残ります
  • astore_1 は、ローカル変数配列のインデックス1への元の参照を格納します。 接頭辞「a」は、格納されるアイテムがオブジェクト参照であり、「1」が配列インデックスであることを意味します。

今後、ローカル変数配列の 2番目の項目(インデックス1)は、新しく作成されたオブジェクトへの参照になります。 したがって、参照を失うことはなく、コンストラクターが何も返さない場合でも、割り当ては実際に機能します。

4. 結論

このクイックチュートリアルでは、JVMがクラスインスタンスを作成および初期化する方法を学びました。 さらに、インスタンスの初期化が内部でどのように機能するかを確認しました。

JVMをさらに詳しく理解するには、仕様を確認することをお勧めします。