JAvaオブジェクトのクローン
9773 ワード
必要:
実際のプログラミングの過程で、ある時点でAにいくつかの有効値が含まれているオブジェクトAがあり、この場合、Aと完全に同じ新しいオブジェクトBが必要になり、その後Bに対する変更はAの値に影響しないことがよくあります.つまり、AとBは2つの独立したオブジェクトですが、Bの初期値はAオブジェクトによって決定されます.Java言語では,単純な付与文ではこのようなニーズを満たすことができず,このようなニーズを満たすには多くの方法がある.
クローンの実装方法浅いクローン クローンするオブジェクトについて、その基本データ型のプロパティについて、新しく生成されたオブジェクトにコピーします.
非基本データ型のプロパティでは、新しく生成されたオブジェクトに参照されるものは1つだけコピーされます.すなわち、新しく生成されたオブジェクトと元のオブジェクトの非基本データ型のプロパティは同じオブジェクトを指します.
1.java.lang.Cloneableインタフェースの実装
cloneのクラスはなぜCloneableインタフェースを実現するのですか?Cloneableインタフェースは識別インタフェースで、メソッドは含まれていません!この識別子はObjectクラスのclone()メソッドのみを対象としており、
cloneクラスがCloneableインタフェースを実装せず、Objectのclone()メソッド(つまりsuper.Clone()メソッド)を呼び出すと、Objectのclone()メソッドはCloneNotSupportedException異常を放出します.
2.java.lang.Object.clone()メソッドの再ロード
JDK APIの説明文書は、この方法がObjectオブジェクトのコピーを返すと説明している.
説明するのは2つあります.
1つは、コピーオブジェクトが参照ではなく新しいオブジェクトを返します.
2つ目は、コピーオブジェクトとnewオペレータで返される新しいオブジェクトの違いです.このコピーには、オブジェクトの初期情報ではなく、元のオブジェクトの情報が含まれています.
Objectクラスのclone()メソッドを観察するとnativeメソッドであり,nativeメソッドの効率は一般的にjavaの非nativeメソッドよりはるかに高い.
これは、クラスをnewしてから元のオブジェクトの情報を新しいオブジェクトに割り当てるのではなく、Objectのclone()メソッドを使用する理由を説明しています.これもclone機能を実現していますが.
Objectクラスのclone()はprotected属性のメソッドで、リロード後にclone()メソッドの属性をpublicに設定します.
Objectクラスにおけるclone()メソッドの効果は次のとおりです.
メモリに元のオブジェクトと同じスペースを開き、元のオブジェクトの内容をそのままコピーします.
基本データ型に対しては、このような操作は問題ありません.
しかし、非基本タイプ変数については、オブジェクトの参照のみが保存されていることがわかります.これにより、clone後の非基本タイプ変数と元のオブジェクトの対応する変数が同じオブジェクトを指していることがわかります.
深度クローン 浅いクローンに基づいて、クローンするオブジェクトの非基本データ型のプロパティに対応するクラスに対してもクローンが実装されます.これにより、非基本データ型のプロパティに対して、コピーされるのは参照ではありません.つまり、新しく生成されたオブジェクトと元のオブジェクトの非基本データ型のプロパティが同じオブジェクトを指しているわけではありません.
クローンするクラスとクラス内のすべての非基本データ型の属性に対応するクラス
1.java.lang.Cloneableインタフェースを実現
2.java.lang.Object.clone()メソッドをすべてリロード
オブジェクトのシーケンス化と逆シーケンス化による深度クローン の実装
オブジェクトシーケンス化とは,オブジェクトの状態をバイトストリームに変換し,後でこれらの値から同じ状態のオブジェクトを生成することである.
オブジェクトのシーケンス化にはもう一つ無視されやすい機能がオブジェクトコピー(Clone)であり、JavaではCloneメカニズムでほとんどのオブジェクトをコピーすることができますが、よく知られているように、Cloneには深さCloneと浅さCloneがあり、オブジェクトが非常に複雑で深層Cloneを実現したい場合は、シーケンス化を使用すれば10行を超えないコードで解決できます.
Javaのシーケンス化は非常に簡単で強力ですが、うまく使うには注意が必要な点がたくさんあります.たとえば、オブジェクトがシーケンス化されていたが、何らかの理由でクラスが少し変更され、再コンパイルされると、さっきのオブジェクトが逆シーケンス化され、異常が発生します.この問題はserialVersionUIDプロパティを追加することで解決できます.もしあなたのクラスが単一のクラスであれば、ユーザーがシーケンス化メカニズムを通じてクラスをコピーすることを許可するかどうか、もしあなたがクラスの実現に慎重に対処する必要があることを許可しないならば.
実際のプログラミングの過程で、ある時点でAにいくつかの有効値が含まれているオブジェクトAがあり、この場合、Aと完全に同じ新しいオブジェクトBが必要になり、その後Bに対する変更はAの値に影響しないことがよくあります.つまり、AとBは2つの独立したオブジェクトですが、Bの初期値はAオブジェクトによって決定されます.Java言語では,単純な付与文ではこのようなニーズを満たすことができず,このようなニーズを満たすには多くの方法がある.
クローンの実装方法
非基本データ型のプロパティでは、新しく生成されたオブジェクトに参照されるものは1つだけコピーされます.すなわち、新しく生成されたオブジェクトと元のオブジェクトの非基本データ型のプロパティは同じオブジェクトを指します.
1.java.lang.Cloneableインタフェースの実装
cloneのクラスはなぜCloneableインタフェースを実現するのですか?Cloneableインタフェースは識別インタフェースで、メソッドは含まれていません!この識別子はObjectクラスのclone()メソッドのみを対象としており、
cloneクラスがCloneableインタフェースを実装せず、Objectのclone()メソッド(つまりsuper.Clone()メソッド)を呼び出すと、Objectのclone()メソッドはCloneNotSupportedException異常を放出します.
2.java.lang.Object.clone()メソッドの再ロード
JDK APIの説明文書は、この方法がObjectオブジェクトのコピーを返すと説明している.
説明するのは2つあります.
1つは、コピーオブジェクトが参照ではなく新しいオブジェクトを返します.
2つ目は、コピーオブジェクトとnewオペレータで返される新しいオブジェクトの違いです.このコピーには、オブジェクトの初期情報ではなく、元のオブジェクトの情報が含まれています.
Objectクラスのclone()メソッドを観察するとnativeメソッドであり,nativeメソッドの効率は一般的にjavaの非nativeメソッドよりはるかに高い.
これは、クラスをnewしてから元のオブジェクトの情報を新しいオブジェクトに割り当てるのではなく、Objectのclone()メソッドを使用する理由を説明しています.これもclone機能を実現していますが.
Objectクラスのclone()はprotected属性のメソッドで、リロード後にclone()メソッドの属性をpublicに設定します.
Objectクラスにおけるclone()メソッドの効果は次のとおりです.
メモリに元のオブジェクトと同じスペースを開き、元のオブジェクトの内容をそのままコピーします.
基本データ型に対しては、このような操作は問題ありません.
しかし、非基本タイプ変数については、オブジェクトの参照のみが保存されていることがわかります.これにより、clone後の非基本タイプ変数と元のオブジェクトの対応する変数が同じオブジェクトを指していることがわかります.
public class User implements Cloneable{
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
protected User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
}
クローンするクラスとクラス内のすべての非基本データ型の属性に対応するクラス
1.java.lang.Cloneableインタフェースを実現
2.java.lang.Object.clone()メソッドをすべてリロード
public class Address implements Cloneable {
private String address;
private Integer no;
public Address clone() throws CloneNotSupportedException {
return (Address)super.clone();
}
}
public class User implements Cloneable {
private String name;
private Address addr;
public User clone() throws CloneNotSupportedException{
return (User)super.clone();
}
}
オブジェクトシーケンス化とは,オブジェクトの状態をバイトストリームに変換し,後でこれらの値から同じ状態のオブジェクトを生成することである.
オブジェクトのシーケンス化にはもう一つ無視されやすい機能がオブジェクトコピー(Clone)であり、JavaではCloneメカニズムでほとんどのオブジェクトをコピーすることができますが、よく知られているように、Cloneには深さCloneと浅さCloneがあり、オブジェクトが非常に複雑で深層Cloneを実現したい場合は、シーケンス化を使用すれば10行を超えないコードで解決できます.
Javaのシーケンス化は非常に簡単で強力ですが、うまく使うには注意が必要な点がたくさんあります.たとえば、オブジェクトがシーケンス化されていたが、何らかの理由でクラスが少し変更され、再コンパイルされると、さっきのオブジェクトが逆シーケンス化され、異常が発生します.この問題はserialVersionUIDプロパティを追加することで解決できます.もしあなたのクラスが単一のクラスであれば、ユーザーがシーケンス化メカニズムを通じてクラスをコピーすることを許可するかどうか、もしあなたがクラスの実現に慎重に対処する必要があることを許可しないならば.
public class Address{
private String address;
private Integer no;
}
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private String name;
private Address addr;
public User clone() {
ByteArrayOutputStream byteOut = null;
ObjectOutputStream objOut = null;
ByteArrayInputStream byteIn = null;
ObjectInputStream objIn = null;
try {
byteOut = new ByteArrayOutputStream();
objOut = new ObjectOutputStream(byteOut);
objOut.writeObject(this);
byteIn = new ByteArrayInputStream(byteOut.toByteArray());
objIn = new ObjectInputStream(byteIn);
return (User) objIn.readObject();
} catch (IOException e) {
throw new RuntimeException("Clone Object failed in IO.",e);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Class not found.",e);
} finally{
try{
byteIn = null;
byteOut = null;
if(objOut != null)
objOut.close();
if(objIn != null)
objIn.close();
}catch(IOException e){
}
}
}
}