2016-08-31 10 views
0

私はJavaの基本的な側面のいくつかを再考しており、浅いクローニングと深いクローンニングに疑問を抱いています。私はそれらを細かく知っており、内部を知っています。浅いクローニングと深いクローニング

public class Department { 
    String deptName; 

    public String getdName() { 
     return deptName; 
    } 

    public void setdName(String dName) { 
     this.deptName = dName; 
    } 

    public Department() { 
     super(); 
    } 

    public Department(String dName) { 
     super(); 
     this.deptName = dName; 
    } 
} 

Employeeクラス - -

省クラス - しかし、私はこの単純な運動につまずい

public class Employee implements Cloneable{ 
    int empNo; 
    String empName; 
    Department dept; 

    public int getEmpNo() { 
     return empNo; 
    } 
    public void setEmpNo(int empNo) { 
     this.empNo = empNo; 
    } 
    public String getEmpName() { 
     return empName; 
    } 
    public void setEmpName(String empName) { 
     this.empName = empName; 
    } 
    public Department getDept() { 
     return dept; 
    } 
    public void setDept(Department dept) { 
     this.dept = dept; 
    } 
    public Employee(int empNo, String empName, Department dept) { 
     super(); 
     this.empNo = empNo; 
     this.empName = empName; 
     this.dept = dept; 
    } 
    public Object clone() throws CloneNotSupportedException { 
     return super.clone(); 
    } 
} 

メインクラス -

public class ShalowCopyTest { 

    public static void main(String args[]) { 
     Department dept1 = new Department("Development"); 
     Department dept2 = new Department("Testing"); 
     Employee emp1 = new Employee(10, "Peter", dept1); 
     Employee emp2 = null; 
     try { 
      emp2 = (Employee) emp1.clone(); 
     } catch (CloneNotSupportedException e) { 
      e.printStackTrace(); 
     } 
     System.out.println(emp1.getDept().getdName()); 
     System.out.println(emp2.getDept().getdName()); 

     System.out.println("Now changing emp1.dept"); 
     //emp1.setDept(dept2); //This is deep cloning - why? 
     emp1.getDept().setdName("Testing"); //This is shallow cloning 
     System.out.println(emp1.getDept().getdName()); 
     System.out.println(emp2.getDept().getdName()); 
    } 
} 

あなたが見ることができ、私が使用している場合は、そのemp1.setDept(dept2)、emp1のdeptを変更してもemp2には影響しません。これは深いクローニングです。しかし、emp1.getDept()。setdName( "Testing")だけでdNameを変更すると、emp2のdNameも変更されます。これは浅いクローンです。なぜこれら2つのラインが違いを生み出していますか?なぜ彼らは同じではありませんか?おかげさまで

+1

ここでは、リンゴとオレンジをIMOと比較しています。どちらの行でも何かがスティックになるはずです。最初のケースでは、部門を更新し、2番目のケースでは名前を更新しました。 –

+0

こんにちは@TimBiegeleisen、ありがとう!問題は、元のdeptの名前を直接変更した場合、元の参照が更新されるということです。その場合、別のコピーを作成せずにそこに変更を加えるだけです。元のものを更新するだけで、emp1とemp2の両方に影響します。しかし、私が部署全体を変更すると、部署の別のコピーを作成してそれをクローンに割り当てています。だから、なぜこの場合、それは別のdept参照を作成していますか?コードのどの部分がそういうことを言っているのですか? setDept()メソッドが表示されたら、this.dept = dept - >は浅いクローニングを意味します! –

+0

new()を使用して新しい部門を作成し、後でそれを変更していません!どちらのコピーコンストラクタもどこにも使用していません。だからすべてが浅いです。しかし、this.dept = deptは新しい参照を作成しており、それは私の質問です。それは意図された行動ですか?ありがとう。 –

答えて

1

私はあなたがこのリンク上と同じ例を使用している気づい:A Guide to Object Cloning in Java

おそらくあなたはすでにsuper.cloneのデフォルトの実装(ということを知っている)の代わりにディープコピーのシャローコピーを行います。

この場合、オブジェクトインスタンスemp1とemp2の両方に、メモリ内の同じ場所を参照する参照が含まれます。 Departmentインスタンスを参照すると、emp1オブジェクトがクローンされた後にメモリ内で参照されます。 enter image description here 両方とも、不変のString: "Development"を含むメモリ内の同じ場所を参照します。設定することにより

emp1.setDept(dept2); 

それは新しいオブジェクトDEPT2へEMP1の参照を変更します。この場合、 enter image description here

あなたは深いコピーとしてではなく、実際にそれを見るだろうではありません。 emp1がメモリ内の新しい場所への参照を変更しただけです。

あなたが設定された他のケースでは:あなたが「テスト」にDepartmanの名前を変更します

emp1.getDept().setdName("Testing"); 

- 両方のオブジェクトインスタンスに表示されます。

質問がありましたら教えてください。

+0

こんにちは@Luisa Bradusca、あなたのメッセージのおかげで。はい、どちらの場合も、浅いコピーですが、emp1.setDept(dept2)を実行しているときに限り、参照は異なる場所を指していることを理解しています。この問題は、コピーコンストラクタでも再現できます。 'Line1:System.out.println(orig.getDept()== copy1.getDept()); //クローンまたはコンストラクタの後にTrueを返します。 ケース1:orig.setDept(dept2); ケース2:orig.getDept()。setdName( "Testing"); Line2:System.out.println(orig.getDept()== copy1.getDept()); Case1ではLine2がfalseを返しますが、Case2の場合はLine2がtrueになります。 –

+0

これは私の主な質問です。orig.setDept(dept2)の前に、origとcopyの両方の参照は同じ場所を指していました。しかしorig.setDept(dept2)の後、彼らは離れて別の場所を指し始めました。しかしorig.getDept().setdName( "Testing")の後でさえ、彼らはまだ同じ場所を指しています!これら2つのセットでは基本的に何が違うのですか?ありがとう。 –

+0

こんにちは@NirmalyaSinha、ケース1:ステップ1)クローンを作成します。ステップ2)set:orig.setDept(dept2)。この後、orig.getDept()!= copy1.getDept()も述べたように、部門参照を切り離して別の場所を指しているからです。ケース2:ステップ1)クローンを作成します。ステップ2)set:orig.getDept()。setdName( "Testing")。この後、orig.getDept()== copy1.getDept()、クローン作成後、両方とも同じオブジェクトを参照し、orig.getDept()。setdName( "Testing")は、両方のオブジェクトが参照する部門の名前を変更します。 –

1

あなたの例は浅く、深いコピーです。深いコピーがあるようです。

複製するオブジェクト(Employee)に複合データ型(Department)があります。他のオブジェクトを含むオブジェクトをクローンすると、実際のオブジェクトではなく参照のみがコピーされます。

のは、あなたのコードを見てみましょう:あなたは(両方とも、クローンと元に影響を与えることになる)実際のインスタンスを変更されていませんが、あなたが代入されている。この場合

emp1.setDept(dept2) 

新しいオブジェクトdeptのインスタンスemp1。したがって、の異なるインスタンスがemp1emp2にあります。そういうわけで、あなたは深いコピーを持っているようです。

のは、あなたが必要なすべての方法であなたの部門の内部で別のインスタンス変数を持つことになりましょう:

public class Department { 
    String deptName; 
    int someNumber; 

    public void setNumber(int number){ 
    someNumber=number; 
    } 

    public int getNumber(){ 
    return someNumber 
    } 


    public Department(String dName, int number){ 
    super(); 
    deptName = dName; 
    someNumber = number; 
    } 
    } 

あなたではmainメソッドあなたがそのような何か:あなたが見ることができるように

Department dept1 = new Department(“Development”, 50); 
Employee emp1 = new Employee(10, “Peter”, dept1); 
Employee emp2 = null; 
emp2 = (Employee) emp1.clone(); 
System.out.println(emp1.getDept().getNumber; // Output: 50 
System.out.println(emp1.getDept().getNumber; // Output: 50 
//Now we change the instance variable of dep1 inside emp1 
emp1.getDept().setNumber(100); 
//Now print the numbers of both employees again 
System.out.println(emp1.getDept().getNumber; // Output: 100 
System.out.println(emp1.getDept().getNumber; // Output: 100 

をそれは浅く深いコピーではありません。 emp1.getDept().setdName(“Testing”)は、文字列が不変であるため、クローンではなくオリジナルを変更する唯一の理由があります。 Stringを変更するたびに新しいStringインスタンスが返されるため、オブジェクトのクローン作成後に元のStringインスタンスに影響を与えません。

あなたの例あなたがそうのようなあなたのcloneメソッドを調整する必要が深いコピーを作成するには: (データ型が一致していると、あなたはもうキャッチ/試みを必要としないので、私もいくつかの小さな調整を行った)

@Override 
public Employee clone(){ 
Employee clone = null; 

try{ 
clone = (Employee)super.clone(); 
clone.Department = Department.clone(); // This is the important line!! You need to clone the Department Object aswell. 
}catch (CloneNotSupportedException e){ 
e.printStackTrace(); 
    } 
return clone; 
} 

もちろん、あなたのDepartment Classが動作するようにするには、Cloneable InterfaceとCloneメソッドを実装する必要があります。

1

super.clone()superObjectなので、すべてのフィールドがコピーされる浅いクローンが得られます。

あなたが始めるのであれば:

EMP1 - > DEPT1 - その後> dname1

emp2 = emp2.clone()、あなたが得る:

EMP1 - > DEPT1 - > dname1 ^ EMP2を----/

つまり、両方とも同じDepartmentオブジェクトを指しています。

あなたがdept1.name = dname2を行う場合は、あなたが得るので、あなただけの、DEPT1影響を与える:

EMP1 - > DEPT1 - > dname2 ^ EMP2 ----/

...とemp1.getDepartment().name = dname2は正確に持っています同じ効果 - それはあなたがどのようにオブジェクトに着くかは関係ありません。 > DEPT1 - - > ... //変わらない EMP2 - > DEPT2 - > ... //

EMP1:あなたは今emp2.department = dept2を行う場合は、で終わるよう

は、それは、EMP1に影響を与えません。新しく割り当てられた

深いクローニングを行うには、各レベルを複製する独自のクローンルーチンを作成する必要があります。

これは間違っています。浅いコピーが「うまくいく」という不変のオブジェクトを使用する習慣をつける方がよい - フィールドを変更することは決してできないため、作業しているオブジェクトと同じオブジェクトを共有しているオブジェクトに誤って影響を及ぼすことはできない。

関連する問題