私の目標は、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;
違いは微妙に見えるかもしれませんが、 マルチスレッドコンテキストで大きな違いを生む可能性があります 。不変クラスは本質的にスレッドセーフであり、効果的に不変クラスは安全に公開されている場合にのみスレッドセーフです。
不変クラスを作成するために考慮しなければならないことがいくつかあります。
final
-すでに持っていますprivate
およびfinal
を作成します-コードに適切な変更を加えますList
やDate
などの可変フィールドがある場合、それらをfinal
にするだけでは十分ではありません。メソッドの呼び出しによって状態が変更されないように、getters
から防御コピーを返す必要があります。4番目の点として、クラスにDate
フィールドがあるとすると、そのフィールドのゲッターは次のようになります。
public Date getDate() {
return new Date(this.date.getTime());
}
可変フィールド自体がいくつかの可変フィールドで構成されている場合、防御コピーを作成することは頭痛の種になります。その場合、それぞれを繰り返しコピーする必要があります。この可変フィールドの反復コピーの名前はDeep Copyです。
ディープコピーを自分で実装するのは面倒です。しかし、その問題を区別して、深い防御的なコピーを作成するような要件に陥ったら、クラス設計を再度検討する必要があります。
final
キーワードの場合:
private final String name;
private final String age;
変数をプライベートにし、セッターメソッドを設定しないことは、プリミティブデータ型に対して機能します。クラスにオブジェクトのコレクションがある場合
コレクションオブジェクトでクラスを不変にするには?
コレクションクラスを拡張して独自のコレクションオブジェクトを記述し、プライベート変数を使用し、セッターメソッドは使用しません。または、コレクションオブジェクトのクローンオブジェクトを返します。
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 {
}
これで問題ありませんが、フィールドfinal
も作成します。
また、文字列ではなく、年齢をint
またはdouble
にします。
少し答えを広げます。
final
はImmutable
と同じではありませんが、final
を使用して、特定の方法で使用する場合、特定のものを不変にすることができます。
特定のタイプは不変であり、変更可能な状態のオブジェクトではなく、不変の値を表します。文字列、数値などは不変です。最後に、通常、オブジェクトは最終的に不変の値を参照するデータ構造になりますが、同じフィールド名に新しい値を割り当てることでデータ構造を変更します。
したがって、真に不変なものを作成するには、コンポジションツリーのベースのすべての値に到達するすべてのフィールドに到達するまで、finalが最後まで使用されていることを確認する必要があります。そうしないと、オブジェクトの下から何かが変更される可能性があり、実際には完全に不変ではありません。
答えるには遅すぎますが、この質問を持っている他の人々を助けるかもしれません。
このリンクはもっと役立つと思います詳細: http://javarevisited.blogspot.com/2013/03/how-to-create-immutable-class-object-Java-example-tutorial.html#ixzz40VDQDDL1 =
Studentクラスのフィールドはインスタンスの初期化時にのみ設定できるため、この例はすでに不変オブジェクトです。
オブジェクトを不変にするには、次の手順を実行する必要があります。
これはすでに不変です。セッターを作成していないため、初期化すると内容を変更できません。最終的なキーワードを変数に追加できます。
すべての変数をfinal
として作成し、フィールドを設定するときに、Student
のように新しく設定された値を持つ新しいString
オブジェクトへの参照を返します。
この例に示されているガイドラインに従うだけです(グーグルでの最初の結果): http://www.javapractices.com/topic/TopicAction.do?Id=29
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
「setter
」メソッド(フィールドまたはフィールドによって参照されるオブジェクトを変更するメソッド)を提供しないでください。
すべてのフィールドをfinal
およびprivate
にします。
サブクラスによるメソッドのオーバーライドを許可しないでください。これを行う最も簡単な方法は、クラスをfinal
として宣言することです。
a。より洗練されたアプローチは、constructor
をプライベートにし、ファクトリメソッドでインスタンスを構築することです。
インスタンスフィールドに可変オブジェクトへの参照が含まれる場合、それらのオブジェクトの変更を許可しないでください。
a。可変オブジェクトを変更するメソッドを提供しないでください。
b。可変オブジェクトへの参照を共有しないでください。コンストラクターに渡される外部の可変オブジェクトへの参照を保存しないでください。必要に応じて、コピーを作成し、コピーへの参照を保存します。同様に、メソッドで元のオブジェクトが返されないように、必要に応じて内部可変オブジェクトのコピーを作成します。