1. 概要

簡単に言うと、JVMでオブジェクトを操作する前に、オブジェクトを初期化する必要があります。

次のセクションでは、プリミティブ型とオブジェクトを初期化するさまざまな方法を見ていきます。

2. 宣言対。 初期化

同じページにいることを確認することから始めましょう。

宣言は、変数をそのタイプと名前とともに定義するプロセスです。

ここでは、id変数を宣言しています。

int id;

一方、初期化とは、値を割り当てることです。 例えば:

id = 1;

実例を示すために、nameおよびidプロパティを持つUserクラスを作成します。

public class User {
    private String name;
    private int id;
    
    // standard constructor, getters, setters,
}

次に、初期化するフィールドのタイプに応じて、初期化の動作が異なることがわかります。

3. オブジェクト対。 プリミティブ

Javaは、プリミティブ型と参照型の2種類のデータ表現を提供します。 このセクションでは、初期化に関する2つの違いについて説明します。

Javaには、Javaプリミティブ型と呼ばれる8つの組み込みデータ型があります。 このタイプの変数は、それらの値を直接保持します。

参照タイプは、オブジェクト(クラスのインスタンス)への参照を保持します。 変数が割り当てられているメモリに値を保持するプリミティブ型とは異なり、参照は参照するオブジェクトの値を保持しません。

代わりに、参照は、オブジェクトが配置されているメモリアドレスを格納することによってオブジェクトを指します。

Javaでは、物理メモリアドレスが何であるかを検出できないことに注意してください。 むしろ、オブジェクトを参照するために参照を使用することしかできません。

Userクラスから参照型を宣言して初期化する例を見てみましょう。

@Test
public void whenIntializedWithNew_thenInstanceIsNotNull() {
    User user = new User();
 
    assertThat(user).isNotNull();
}

ここでわかるように、新しいユーザーオブジェクトの作成を担当するキーワード new、を使用して、参照をnewに割り当てることができます。

オブジェクトの作成についてさらに学び続けましょう。

5. オブジェクトの作成

プリミティブとは異なり、オブジェクトの作成は少し複雑です。 これは、フィールドに値を追加するだけではないためです。 代わりに、newキーワードを使用して初期化をトリガーします。 これは、代わりに、コンストラクターを呼び出し、メモリ内のオブジェクトを初期化します。

コンストラクターとnewキーワードについてさらに詳しく説明しましょう。

新しいキーワードは、コンストラクターを介して新しいオブジェクトにメモリを割り当てる責任があります。

コンストラクターは通常、作成されたオブジェクトのメインプロパティを表すインスタンス変数を初期化するために使用されます

コンストラクターを明示的に指定しない場合、コンパイラーは引数を持たず、オブジェクトにメモリーを割り当てるだけのデフォルトのコンストラクターを作成します。

パラメーターリストが異なる(オーバーロード)限り、クラスは多くのコンストラクターを持つことができます。 同じクラス内の別のコンストラクターを呼び出さないすべてのコンストラクターは、明示的に記述されたか、 super()を介してコンパイラーによって挿入されたかに関係なく、親コンストラクターを呼び出します。

Userクラスにコンストラクターを追加しましょう。

public User(String name, int id) {
    this.name = name;
    this.id = id;
}

これで、コンストラクターを使用して、プロパティの初期値を持つUserオブジェクトを作成できます。

User user = new User("Alice", 1);

6. 可変スコープ

次のセクションでは、Javaの変数が存在できるさまざまなタイプのスコープと、これが初期化プロセスにどのように影響するかを見ていきます。

6.1. インスタンス変数とクラス変数

インスタンス変数とクラス変数では、初期化する必要はありません。これらの変数を宣言するとすぐに、次のようなデフォルト値が与えられます。

それでは、いくつかのインスタンスとクラス関連の変数を定義して、それらにデフォルト値があるかどうかをテストしてみましょう。

@Test
public void whenValuesAreNotInitialized_thenUserNameAndIdReturnDefault() {
    User user = new User();
 
    assertThat(user.getName()).isNull();
    assertThat(user.getId() == 0);
}

6.2. ローカル変数

ローカル変数はデフォルト値がなく、コンパイラーが初期化されていない値を使用できないため、使用する前に初期化する必要があります

たとえば、次のコードはコンパイラエラーを生成します。

public void print(){
    int i;
    System.out.println(i);
}

7. Finalキーワード

final キーワードがフィールドに適用されると、初期化後にフィールドの値を変更できなくなります。 このようにして、Javaで定数を定義できます。

Userクラスに定数を追加しましょう。

private static final int YEAR = 2000;

定数は、宣言時またはコンストラクターで初期化する必要があります。

8. Javaのイニシャライザー

Javaでは、イニシャライザーは、関連付けられた名前またはデータ型を持たないコードのブロックであり、メソッド、コンストラクター、または別のコードブロックの外部に配置されます。

Javaには、静的初期化子とインスタンス初期化子の2種類の初期化子があります。 それぞれの使い方を見てみましょう。

8.1. インスタンス初期化子

これらを使用して、インスタンス変数を初期化できます。

実例を示すために、 User クラスのインスタンス初期化子を使用して、ユーザーidに値を指定しましょう。

{
    id = 0;
}

8.2. 静的初期化ブロック

静的初期化子または静的ブロック– staticフィールドを初期化するために使用されるコードのブロックです。 つまり、キーワード static:でマークされた単純な初期化子です。

private static String forum;
static {
    forum = "Java";
}

9. 初期化の順序

もちろん、さまざまなタイプのフィールドを初期化するコードを作成するときは、初期化の順序に注意する必要があります。

Javaでは、初期化ステートメントの順序は次のとおりです。

  • 静的変数と静的初期化子を順番に
  • インスタンス変数とインスタンス初期化子を順番に
  • コンストラクター

10. オブジェクトのライフサイクル

オブジェクトを宣言して初期化する方法を学習したので、オブジェクトが使用されていないときにオブジェクトがどうなるかを見てみましょう。

オブジェクトの破壊を心配しなければならない他の言語とは異なり、Javaはガベージコレクターを介して廃止されたオブジェクトを処理します。

Java内のすべてのオブジェクトは、プログラムのヒープメモリに格納されます。 実際、ヒープは、Javaアプリケーションに割り当てられた未使用のメモリの大きなプールを表しています。

一方、ガベージコレクターは、到達不能になったオブジェクトを削除することで自動メモリ管理を処理するJavaプログラムです。

Javaオブジェクトが到達不能になるには、次のいずれかの状況が発生する必要があります。

  • オブジェクトには、それを指す参照がなくなりました
  • オブジェクトを指すすべての参照は範囲外です

結論として、オブジェクトは最初にクラスから作成され、通常はキーワードを使用します新着。 次に、オブジェクトはその寿命を生き、そのメソッドとフィールドへのアクセスを提供します。

最後に、不要になると、ガベージコレクターはそれを破棄します。

11. オブジェクトを作成するための他のメソッド

このセクションでは、オブジェクトを作成するためのnewキーワード以外のメソッドと、それらを適用する方法、具体的にはリフレクション、クローン作成、およびシリアル化について簡単に説明します。

Reflectionは、実行時にクラス、フィールド、およびメソッドを検査するために使用できるメカニズムです。リフレクションを使用してUserオブジェクトを作成する例を次に示します。

@Test
public void whenInitializedWithReflection_thenInstanceIsNotNull() 
  throws Exception {
    User user = User.class.getConstructor(String.class, int.class)
      .newInstance("Alice", 2);
 
    assertThat(user).isNotNull();
}

この場合、リフレクションを使用して、Userクラスのコンストラクターを見つけて呼び出しています。

次のメソッドcloningは、オブジェクトの正確なコピーを作成する方法です。このために、UserクラスはCloneableインターフェイスを実装する必要があります。

public class User implements Cloneable { //... }

これで、 clone()メソッドを使用して、userオブジェクトと同じプロパティ値を持つ新しいclonedUserオブジェクトを作成できます。

@Test
public void whenCopiedWithClone_thenExactMatchIsCreated() 
  throws CloneNotSupportedException {
    User user = new User("Alice", 3);
    User clonedUser = (User) user.clone();
 
    assertThat(clonedUser).isEqualTo(user);
}

sun.misc.Unsafe クラスを使用して、コンストラクターを呼び出さずにオブジェクトにメモリを割り当てることもできます。

User u = (User) unsafeInstance.allocateInstance(User.class);

12. 結論

このチュートリアルでは、Javaでのフィールドの初期化について説明しました。 Javaでさまざまなデータ型とその使用方法を発見しました。 また、Javaでオブジェクトを作成するいくつかの方法についても詳しく説明しました。

このチュートリアルの完全な実装は、Githubにあります。