JAVA-可変オブジェクトと可変オブジェクト
5248 ワード
可変オブジェクトは、コンカレント・プログラムで役立ちます.ステータスが変更できないため、スレッドの干渉によって破損したり、不一致と見なされたりすることはできません.
基本概念
*可変オブジェクト(Immutable Objects)つまり、オブジェクトが作成されるとその状態(オブジェクトのデータ、すなわちオブジェクトの属性値)は変更されず、その変更に対して新しいオブジェクトが生成されるべきである.
*可変オブジェクト(Mutable Objects):可変クラスに対して、可変クラスはインスタンスを作成した後、そのメンバー変数の値を変更することができ、開発で作成したクラスの大部分は可変クラスに属します.
*可変オブジェクトのクラスは、可変クラス(Immutable Class)です.JAVAプラットフォームクラスライブラリには、String、基本タイプのパッケージクラス、BigInteger、BigDecimalなど、多くの可変クラスが含まれています.
可変クラスの作成
以下の点に従って、可変クラスを作成できます.
A.クラスが継承されないことを確認します.クラスをfinalと宣言するか、静的ファクトリを使用してコンストラクタをprivateと宣言します.クラスを継承できる場合、クラスの不変性メカニズムが破壊されます.クラスが親を上書きするメソッドを継承し、継承クラスがメンバー変数値を変更できる限り、子クラスが親として現れると、現在のクラスが可変であるかどうかは保証されません.
B.privateとfinal修飾子を用いてクラスの属性を修飾する
注意:メンバー属性が可変オブジェクト属性の場合、これらのオブジェクトを変更しないでください.
1)可変オブジェクトを変更する方法を提供しない
2)可変オブジェクトへの参照を共有しないでください.コンストラクタの外部可変オブジェクトへの参照を保存しないでください.可変オブジェクトを参照するメンバー変数と外部可変オブジェクトの参照が同じメモリアドレスを指すため、ユーザーは可変クラス以外で可変オブジェクトの値を変更できます.
内部の値が変更されないことを保証するために、深度コピーの方法を使用して、オブジェクトをコピーし、コピーの参照を入力してクラスの可変性を確保できます.
必要に応じてクラス内のメソッドは、元のオブジェクトではなく内部可変オブジェクトのコピーを返します.
C.オブジェクトの状態を変更できる方法を提供しない(set方法だけでなく、他の状態を変更できる方法もある)
例を挙げます.
実行結果:
the value of fDateOfDiscovery of internal class : 1393943752205the value of date after change its value : 111111111
可変オブジェクトのメリットとデメリット
メリット:
*構造、テスト、使用は簡単
*可変オブジェクトはスレッドが安全で、スレッド間で共有できます.オブジェクトの値が変更できないため、同期の問題を保証するために特別なメカニズムを使用する必要はありません.一部のロックメカニズムなどでメモリの一貫性を保証する必要がないため、同時エラーの可能性を低減できます.
*可変オブジェクトは、文字列の字面量や整数値のように、繰り返し使用するためにキャッシュされます.スタティックファクトリメソッドを使用して、valueOf()のようなメソッドを提供することができ、キャッシュから既存のImmutableオブジェクトを再作成するのではなく、キャッシュから返すことができます.
欠点:
*可変オブジェクトの最大の欠点は、オブジェクトの作成にかかるコストです.各ステップの操作によって新しいオブジェクトが生成され、大量のゴミが作成されます.再利用できないため、それらの使用は「使用」であり、「廃棄」であり、多くのゴミが作成され、ゴミ収集に大きな迷惑をかけます.
基本概念
*可変オブジェクト(Immutable Objects)つまり、オブジェクトが作成されるとその状態(オブジェクトのデータ、すなわちオブジェクトの属性値)は変更されず、その変更に対して新しいオブジェクトが生成されるべきである.
*可変オブジェクト(Mutable Objects):可変クラスに対して、可変クラスはインスタンスを作成した後、そのメンバー変数の値を変更することができ、開発で作成したクラスの大部分は可変クラスに属します.
*可変オブジェクトのクラスは、可変クラス(Immutable Class)です.JAVAプラットフォームクラスライブラリには、String、基本タイプのパッケージクラス、BigInteger、BigDecimalなど、多くの可変クラスが含まれています.
可変クラスの作成
以下の点に従って、可変クラスを作成できます.
A.クラスが継承されないことを確認します.クラスをfinalと宣言するか、静的ファクトリを使用してコンストラクタをprivateと宣言します.クラスを継承できる場合、クラスの不変性メカニズムが破壊されます.クラスが親を上書きするメソッドを継承し、継承クラスがメンバー変数値を変更できる限り、子クラスが親として現れると、現在のクラスが可変であるかどうかは保証されません.
B.privateとfinal修飾子を用いてクラスの属性を修飾する
注意:メンバー属性が可変オブジェクト属性の場合、これらのオブジェクトを変更しないでください.
1)可変オブジェクトを変更する方法を提供しない
2)可変オブジェクトへの参照を共有しないでください.コンストラクタの外部可変オブジェクトへの参照を保存しないでください.可変オブジェクトを参照するメンバー変数と外部可変オブジェクトの参照が同じメモリアドレスを指すため、ユーザーは可変クラス以外で可変オブジェクトの値を変更できます.
public final class ImmutableDemo {
private final int[] myArray;
public ImmutableDemo(int[] array) {
this.myArray = array; // wrong
}
}
内部の値が変更されないことを保証するために、深度コピーの方法を使用して、オブジェクトをコピーし、コピーの参照を入力してクラスの可変性を確保できます.
public final class MyImmutableDemo {
private final int[] myArray;
public MyImmutableDemo(int[] array) {
this.myArray = array.clone();
}
}
必要に応じてクラス内のメソッドは、元のオブジェクトではなく内部可変オブジェクトのコピーを返します.
C.オブジェクトの状態を変更できる方法を提供しない(set方法だけでなく、他の状態を変更できる方法もある)
例を挙げます.
import java.util.Date;
public final class Planet {
// final
private final double fMass;
// (String )
private final String fName;
// , ,
private final Date fDateOfDiscovery;
public Planet(double aMass, String aName, Date aDateOfDiscovery) {
fMass = aMass;
fName = aName;
// aDateOfDiscovery
// fDateOfDiscovery private ,
// aDateOfDiscovery
fDateOfDiscovery = new Date(aDateOfDiscovery.getTime());
}
// .
public double getMass() {
return fMass;
}
// . String
public String getName() {
return fName;
}
// . Date ,
// . ? fDate . ,
// fDate Date
public Date getDateOfDiscovery() {
return new Date(fDateOfDiscovery.getTime());
}
public static void main(String[] args) {
Planet planet = new Planet(1.0D, "earth", new Date());
Date date = planet.getDateOfDiscovery();
date.setTime(111111111L);
System.out.println("the value of fDateOfDiscovery of internal class : " + planet.fDateOfDiscovery.getTime());
System.out.println("the value of date after change its value : " + date.getTime());
}
}
実行結果:
the value of fDateOfDiscovery of internal class : 1393943752205the value of date after change its value : 111111111
可変オブジェクトのメリットとデメリット
メリット:
*構造、テスト、使用は簡単
*可変オブジェクトはスレッドが安全で、スレッド間で共有できます.オブジェクトの値が変更できないため、同期の問題を保証するために特別なメカニズムを使用する必要はありません.一部のロックメカニズムなどでメモリの一貫性を保証する必要がないため、同時エラーの可能性を低減できます.
*可変オブジェクトは、文字列の字面量や整数値のように、繰り返し使用するためにキャッシュされます.スタティックファクトリメソッドを使用して、valueOf()のようなメソッドを提供することができ、キャッシュから既存のImmutableオブジェクトを再作成するのではなく、キャッシュから返すことができます.
public class CacheImmutale {
private final String name;
private static CacheImmutale[] cache = new CacheImmutale[10];
private static int pos = 0;
public CacheImmutale(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public static CacheImmutale valueOf(String name) {
//
for (int i = 0; i < pos; i++) {
// ,
if (cache[i] != null && cache[i].getName().equals(name)) {
return cache[i];
}
}
//
if (pos == 10) {
//
cache[0] = new CacheImmutale(name);
pos = 1;
return cache[0];
} else {
// ,pos 1
cache[pos++] = new CacheImmutale(name);
return cache[pos - 1];
}
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof CacheImmutale) {
CacheImmutale ci = (CacheImmutale) obj;
if (name.equals(ci.getName())) {
return true;
}
}
return false;
}
public static void main(String[] args) {
CacheImmutale c1 = CacheImmutale.valueOf("hello");
CacheImmutale c2 = CacheImmutale.valueOf("hello");
System.out.println(c1 == c2);// true
}
}
欠点:
*可変オブジェクトの最大の欠点は、オブジェクトの作成にかかるコストです.各ステップの操作によって新しいオブジェクトが生成され、大量のゴミが作成されます.再利用できないため、それらの使用は「使用」であり、「廃棄」であり、多くのゴミが作成され、ゴミ収集に大きな迷惑をかけます.