web-dev-qa-db-ja.com

不変にするJavaオブジェクト

私の目標は、Javaオブジェクトを不変にします。クラスStudentがあります。不変を実現するために、次の方法でコーディングしました。

public final class Student {

private String name;
private String age;

public Student(String name, String age) {
    this.name = name;
    this.age = age;
}

public String getName() {
    return name;
}

public String getAge() {
    return age;
}

}

私の質問は、Studentクラスの不変性を達成する最良の方法は何ですか?

厳密に言えば、クラスは不変ではなく、事実上不変です。不変にするには、finalを使用する必要があります。

private final String name;
private final String age;

違いは微妙に見えるかもしれませんが、 マルチスレッドコンテキストで大きな違いを生む可能性があります 。不変クラスは本質的にスレッドセーフであり、効果的に不変クラスは安全に公開されている場合にのみスレッドセーフです。

66
assylias

不変クラスを作成するために考慮しなければならないことがいくつかあります。

  • クラスを作成final-すでに持っています
  • すべてのフィールドprivateおよびfinalを作成します-コードに適切な変更を加えます
  • インスタンスの状態を変更するメソッドを提供しないでください
  • クラスにListDateなどの可変フィールドがある場合、それらをfinalにするだけでは十分ではありません。メソッドの呼び出しによって状態が変更されないように、gettersから防御コピーを返す必要があります。

4番目の点として、クラスにDateフィールドがあるとすると、そのフィールドのゲッターは次のようになります。

public Date getDate() {
    return new Date(this.date.getTime());
}

可変フィールド自体がいくつかの可変フィールドで構成されている場合、防御コピーを作成することは頭痛の種になります。その場合、それぞれを繰り返しコピーする必要があります。この可変フィールドの反復コピーの名前はDeep Copyです。

ディープコピーを自分で実装するのは面倒です。しかし、その問題を区別して、深い防御的なコピーを作成するような要件に陥ったら、クラス設計を再度検討する必要があります。

56
Rohit Jain
  1. 拡張できないように、クラスを最終として宣言します。
  2. すべてのフィールドをプライベートにして、直接アクセスが許可されないようにします。
  3. 変数の設定メソッドを提供しないでください
  4. すべての可変フィールドを最終的なものにして、値を1回だけ割り当てられるようにします。
  5. ディープコピーを実行するコンストラクターを介してすべてのフィールドを初期化します。
  6. 実際のオブジェクト参照を返すのではなく、ゲッターメソッドでオブジェクトのクローンを作成してコピーを返します。

ソース

4
Premraj

finalキーワードの場合:

private final String name;
private final String age;
3

変数をプライベートにし、セッターメソッドを設定しないことは、プリミティブデータ型に対して機能します。クラスにオブジェクトのコレクションがある場合

コレクションオブジェクトでクラスを不変にするには?

コレクションクラスを拡張して独自のコレクションオブジェクトを記述し、プライベート変数を使用し、セッターメソッドは使用しません。または、コレクションオブジェクトのクローンオブジェクトを返します。

public final class Student {

private StudentList names;//Which is extended from arraylist

public Student() {
names = DAO.getNamesList()//Which will return All Student names from Database  its upto you how you want to implement.
}

public StudentList getStudentList(){
return names;//you need to implement your own methods in StudentList class to iterate your arraylist; or you can return Enumeration object.
}

public Enumeration getStudentNamesIterator(
Enumeration e = Collections.enumeration(names);
return e;
}

public class StudentList extends ArrayList {

}
3
user4485029

これで問題ありませんが、フィールドfinalも作成します。

また、文字列ではなく、年齢をintまたはdoubleにします。

2
Peter Lawrey

少し答えを広げます。

finalImmutableと同じではありませんが、finalを使用して、特定の方法で使用する場合、特定のものを不変にすることができます。

特定のタイプは不変であり、変更可能な状態のオブジェクトではなく、不変の値を表します。文字列、数値などは不変です。最後に、通常、オブジェクトは最終的に不変の値を参照するデータ構造になりますが、同じフィールド名に新しい値を割り当てることでデータ構造を変更します。

したがって、真に不変なものを作成するには、コンポジションツリーのベースのすべての値に到達するすべてのフィールドに到達するまで、finalが最後まで使用されていることを確認する必要があります。そうしないと、オブジェクトの下から何かが変更される可能性があり、実際には完全に不変ではありません。

2
Chris Travers

答えるには遅すぎますが、この質問を持っている他の人々を助けるかもしれません。

  1. 不変オブジェクトの状態は、構築後に変更できません。変更すると、新しい不変オブジェクトが生成されます。
  2. Immutableクラスのすべてのフィールドはfinalでなければなりません。
  3. オブジェクトは適切に構築する必要があります。つまり、構築プロセス中にオブジェクト参照がリークしてはなりません。
  4. 親クラスの不変性を変更するためにサブクラスを制限するために、オブジェクトはfinalでなければなりません。

このリンクはもっと役立つと思います詳細: http://javarevisited.blogspot.com/2013/03/how-to-create-immutable-class-object-Java-example-tutorial.html#ixzz40VDQDDL1 =

1
Yirga

Studentクラスのフィールドはインスタンスの初期化時にのみ設定できるため、この例はすでに不変オブジェクトです。

オブジェクトを不変にするには、次の手順を実行する必要があります。

  1. クラスのフィールドを変更する可能性のあるメソッドは使用しないでください。たとえば、セッターを使用しないでください。
  2. パブリックの非最終フィールドの使用は避けてください。フィールドがパブリックの場合、それらをfinalとして宣言し、コンストラクターで、または宣言行で直接初期化する必要があります。
1
Eldar Agalarov

これはすでに不変です。セッターを作成していないため、初期化すると内容を変更できません。最終的なキーワードを変数に追加できます。

0
Nick C

すべての変数をfinalとして作成し、フィールドを設定するときに、Studentのように新しく設定された値を持つ新しいStringオブジェクトへの参照を返します。

0
dev-null

この例に示されているガイドラインに従うだけです(グーグルでの最初の結果): http://www.javapractices.com/topic/TopicAction.do?Id=29

0
JPetric

Java:1.で不変オブジェクトの状態を変更することはできません。変更すると新しい不変オブジェクトになります。2。すべてのフィールドオブジェクトは適切に構築する必要があります。つまり、オブジェクト参照は構築プロセス中にリークしてはなりません4.オブジェクトは親クラスの不変性を変更するためにサブクラスを制限するためにfinalにする必要があります。

例:

public final class Contacts {

private final String name;
private final String mobile;

public Contacts(String name, String mobile) {
    this.name = name;
    this.mobile = mobile;
}

public String getName(){
    return name;
}

public String getMobile(){
    return mobile;
}

}

このリンクを参照してください: http://javarevisited.blogspot.in/2013/03/how-to-create-immutable-class-object-Java-example-tutorial.html

0
Vijay Bhatt

不変オブジェクト定義の戦略

  1. setter」メソッド(フィールドまたはフィールドによって参照されるオブジェクトを変更するメソッド)を提供しないでください。

  2. すべてのフィールドをfinalおよびprivateにします。

  3. サブクラスによるメソッドのオーバーライドを許可しないでください。これを行う最も簡単な方法は、クラスをfinalとして宣言することです。

    a。より洗練されたアプローチは、constructorをプライベートにし、ファクトリメソッドでインスタンスを構築することです。

  4. インスタンスフィールドに可変オブジェクトへの参照が含まれる場合、それらのオブジェクトの変更を許可しないでください。

    a。可変オブジェクトを変更するメソッドを提供しないでください。

    b。可変オブジェクトへの参照を共有しないでください。コンストラクターに渡される外部の可変オブジェクトへの参照を保存しないでください。必要に応じて、コピーを作成し、コピーへの参照を保存します。同様に、メソッドで元のオブジェクトが返されないように、必要に応じて内部可変オブジェクトのコピーを作成します。

0