トピックを正式に入力する前に、まずディープコピーと事前コピーの概念を理解しましょう。
ライトコピー:
新しいオブジェクトが作成されます。これには、元のオブジェクトのプロパティ値の正確なコピーがあります。属性が基本タイプの場合、基本タイプの値がコピーされます。属性がメモリアドレスである場合、メモリアドレスがコピーされるため、オブジェクトがこのアドレスを変更すると、別のオブジェクトに影響します。
ディープコピー:
オブジェクトのすべての非参照メンバー変数値をコピーするだけでなく、参照タイプのメンバー変数の新しいインスタンスを作成し、それを正式なパラメーターインスタンス値に初期化する必要があります。
概念を理解した後、通常のオブジェクト割り当て操作がディープコピーであるか浅いコピーであるかをテストしましょう。
テストコード:
public class depthcopy {public static void main(string [] args){copy first = new copy( "hzw"、24); second = first; second.name = "shanxi"; System.out.println(first.name); // output shanxi}} class copy {public string name;公共のint年齢;パブリックコピー(文字列名、int age){this.name = name; this.age = age; }} Shanxiに名前属性値を2番目に変更した後、ファーストネーム属性値もShanxiになることがわかります。これは、通常のオブジェクトの割り当てが浅いコピーに属していることを示しています。
オブジェクト間の割り当てが浅いコピーであるかどうかを理解した後、クローニングが深いコピーなのか浅いコピーなのかを見てみましょう。テストコードは、上記のコピーオブジェクトがクローン可能なインターフェイスにクローンメソッドを実装できるようにすることです。
public class depthcopy {public static void main(string [] args){copy first = new copy( "hzw"、24); second = nullをコピーします。 try {second =(copy)first.clone(); } catch(clonenotsupportedexception e){e.printstacktrace(); } second.name = "shanxi"; System.out.println(first.name); // output:hzw system.out.println(first); // output:com.hzw.day33.copy@7f39ebdb system.out.println(2番目); // output:com.hzw.day333333333333abb81e cls class class class class class class class公共のint年齢;パブリックコピー(文字列名、int age){this.name = name; this.age = age; } @Override保護されたオブジェクトclone()throws clonenotsupportedexception {return super.clone(); }}最初に作成されたオブジェクトを最初に作成し、2番目にクローンされたオブジェクトが2つのインスタンスであるため、2番目の名前属性の変更は最初の名前属性に影響しないことがわかります。ただし、次の例のように、クローニングが深いコピーであると単純に考えることはできません。
public class depthcopy {public static void main(string [] args){学生= new Student(95); first = new Copy( "HZW"、24、sudent)をコピーします。 second = nullをコピーします。 try {second =(copy)first.clone(); } catch(clonenotsupportedexception e){e.printstacktrace(); } second.name = "shanxi"; second.student.score = 60; System.out.println(first == second); // false System.out.println(first.student == second.student); // true system.out.println(first.student.score); // 60}} class copy explments cloneable {public string name;公共のint年齢;公立学生の学生。パブリックコピー(文字列名、int年齢、学生学生){this.name = name; this.age = age; this.student = desutent; } @Override保護されたオブジェクトclone()throws clonenotsupportedexception {return super.clone(); }} class Student {public int score;パブリック学生(intスコア){this.score = score; }}見たことがありますか?クローニングで2番目を作成しましたが、最初と2番目のインスタンスが2つのインスタンスであることは明らかです。最初の== secondの出力は偽ですが、最初と2番目の学生オブジェクトは同じです。学生のスコア値を2番目に変更した後、最初の学生のスコアも変わりました。これは、最初と2番目の学生が同じであることを意味します。これは、クローニングが浅いコピーであることを意味します。クローニングのディープコピーを実装する場合は、コピーオブジェクトのスチューデントオブジェクトにクローン可能なインターフェイスにクローンメソッドを実装し、コピーのクローンメソッドが生徒のクローンを返して、生徒が一意にできるようにする必要があります。変更されたコードは次のとおりです。
public class depthcopy {public static void main(string [] args){学生= new Student(95); first = new Copy( "HZW"、24、sudent)をコピーします。 second = nullをコピーします。 try {second =(copy)first.clone(); } catch(clonenotsupportedexception e){e.printstacktrace(); } second.name = "shanxi"; second.student.score = 60; System.out.println(first == second); // false System.out.println(first.student == second.student); // false System.out.println(first.student.score); // 95 System.out.println(second.student.score); // 60}}}クラスのコピークロニー弦{public cloneable {public cloneable {public cloneable {public cloneable {pubal公共のint年齢;公立学生の学生。パブリックコピー(文字列名、int年齢、学生学生){this.name = name; this.age = age; this.student = desutent; } @Override保護されたオブジェクトclone()throws clonenotsupportedexception {copy copy =(copy)super.clone(); copy.student =(desute)Student.Clone();コピーを返します。 }}クラスの学生はcloneable {public int score;パブリック学生(intスコア){this.score = score; } @Override保護されたオブジェクトclone()throws clonenotsupportedexception {return super.clone(); }} 1番目と2番目、1番目、StudentとSecond.Studentは現時点では同じではありません。したがって、2番目の学生のスコアを変更した後、1人目の学生のスコア値に影響を与えず、ディープコピーの目的を達成します。
ただし、注意深く考えると、問題が発生します。大学のクラスなど、上記の例の学生クラスにも参照型属性がある場合は、カレッジクラスにクローン可能なインターフェイスを実装させ、学生クラスのクローンメソッドでカレッジクラスのクローンメソッドを呼び出し、コピークラスのクローンメソッドで学生クラスのクローンメソッドを呼び出す必要があります。私はそれがなくなったことがわかりました。このプロセスは非常に複雑です。クラス内のすべての関連する参照タイプは、クローン可能なインターフェイスを実装する必要があります。私はそれがとても厄介だと感じています、大丈夫、次のことは素晴らしいことです。
深いコピーの問題を解決する最良の方法は、シリアル化を使用することです。そうすることで、すべてのクラスがクローン可能なインターフェイスを実装し、直接シリアル化して脱暗復する必要がありません。見てみましょう。
java.io.fileをインポートします。 java.io.fileinputStreamをインポートします。 java.io.fileoutputStreamをインポートします。 java.io.objectinputStreamをインポートします。 java.io.objectOutputStreamをインポートします。 java.io.serializableをインポートします。 public class depthcopy {public static void main(string [] args){College School = New College( "nongda");生徒=新しい生徒(95、学校);コピーコピー= new Copy( "HZW"、23、Student);別の= nullをコピーします。 ObjectOutputStream OOS = new objectOutputStream(FOS); oos.writeobject(copy); } catch(Exception e){e.printstacktrace(); } // Deserialization操作FileInputStream fisをシリアル化します。 try {fis = new fileInputStream(new file( "d:/copy.txt")); ObjectInputStream ois = new ObjectInputStream(fis);別の=(コピー)ois.readObject(); } catch(Exception e){e.printstacktrace(); } system.out.println(copy == another); // false system.out.println(copy.student == another.student); // false system.out.println(copy.student.school == another.student.school); // false Another.Student.school. System.out.println(copy.student.school.schoolname); // nongda}} classコピーexplments serializable {public string name;公共のint年齢;公立学生の学生。パブリックコピー(文字列名、int年齢、学生学生){this.name = name; this.age = age; this.student = desutent; }} class学生はSerializable {public int score;公立学校。パブリック学生(intスコア、カレッジスクール){this.score = score; this.school = school; }} class CollegeはSerializable {public String schoolName;パブリックカレッジ(String SchoolName){this.schoolname = schoolName; }}出力から、降下後に生成されたオブジェクトは元のオブジェクトのコピーであり、同じ属性値を除いて元のオブジェクトとの関係がないことがわかります。したがって、Deserialization生成されたオブジェクトの学校名を「WUDA」に変更すると、元のインスタンスのスクール名を変更せず、「Nongda」を出力するため、実際のディープコピー効果を達成しました。ただし、シリアル化を達成するためには、すべての関連するクラスがシリアル化可能なインターフェイスを実装する必要があります。これは、クローン可能なインターフェイスとクローンメソッドの両方を実装するよりも常に便利です。
上記は、Java Deepと浅いコピーの詳細な説明です。必要な場合は、参照してください。