Javaオブジェクトを作成する方法には、new、リフレクション、デシリアライズ、およびコピーが含まれます。では、コピーとは何ですか?浅いコピーと深いコピーの違いは何ですか?
コピーとは
コピーとは、元のオブジェクトのデータの一部または全部を再利用し、元のオブジェクトに基づいてコピーして新しいオブジェクトを作成することです。
Objectクラスにネイティブタイプのクローンメソッドがあります
protected native Object clone() throws CloneNotSupportedException;
オブジェクトをコピーできる場合、そのオブジェクトに対応するクラスは、Cloneableインターフェースを実装し、Objectのcloneメソッドをオーバーライドする必要があります。
Cloneableインターフェースを実装する必要があります。そうしないと、cloneメソッドを呼び出すとjava.lang.CloneNotSupportedExecption例外がスローされます。
//Cloneable接口中没有任何参数或抽象方法,该接口只是一个标识
public interface Cloneable {
}
//如Student类,实现Cloneable接口,重写Object的clone方法
public class Student implements Cloneable{
private String sname;
private Integer sage;
...
@Override
protected Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
}
栗を取る
public class cloneObject {
public static void main(String[] args) throws CloneNotSupportedException {
Student student = new Student("学生1",18);
System.out.println("clone前的Student对象为:"+student);
Student cloneStudent = student.clone();
System.out.println("clone后的Student对象为:"+cloneStudent);
System.out.println("Student对象与cloneStudent对象是否相等:"+student.equals(cloneStudent));
}
}
印刷結果は
clone前的Student对象为:Student{sname='学生1', sage=18}
clone后的Student对象为:Student{sname='学生1', sage=18}
Student对象与cloneStudent对象是否相等:false
コピーすると新しいオブジェクトが作成されることがわかります。
浅いコピーとは何ですか?
説明のために、少し後で生徒のクラスを変更します
StudentクラスのString型とInteger型の属性に加えて、Teacher型の属性が追加されます。TeacherクラスにはString型のtname属性が1つだけあります。
public class Student implements Cloneable{
private String sname;
private Integer sage;
private Teacher teacher;
...
@Override
protected Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
public class Teacher {
private String tname;
sutdentオブジェクトのcloneメソッドを再度呼び出します
public static void main(String[] args) throws CloneNotSupportedException {
Teacher teacher = new Teacher("罗翔老师");
Student student = new Student("学生1",18,teacher);
System.out.println("clone前的Student对象为:"+student);
Student cloneStudent = student.clone();
System.out.println("clone后的Student对象为:"+cloneStudent);
System.out.println("Student对象与cloneStudent对象是否相等:"+student.equals(cloneStudent));
System.out.println("student对象和cloneStudent对象中的teacher属性是否相等:"+student.getTeacher().equals(cloneStudent.getTeacher()));
}
2つのsutdentオブジェクトの比較結果はfalseであると予想されます。ただし、2つの学生オブジェクトの教師プロパティの比較結果は真です。
clone前的Student对象为:Student{sname='学生1', sage=18, teacher=com.hard.qz.clone.Teacher@1b6d3586}
clone后的Student对象为:Student{sname='学生1', sage=18, teacher=com.hard.qz.clone.Teacher@1b6d3586}
Student对象与cloneStudent对象是否相等:false
student对象和cloneStudent对象中的teacher属性是否相等:true
//修改student对象中teacher属性的值,观察cloneStudent对象中的teacher属性的值是否会变
student.getTeacher().setTname("张三老师");
System.out.println("cloneStudent对象中teacher属性的值为:"+cloneStudent.getTeacher());
結果は次のとおりです。
cloneStudent对象中teacher属性的值为:Teacher{tname='张三老师'}
Studentオブジェクトのteacher属性の値を変更すると、cloneStudentオブジェクトのteacher属性の値に影響します。これは、2つのstudentオブジェクトがteacherオブジェクトを共有していることを示しています。
上記の場合、コピーする場合は一部のプロパティのみがコピーされ、オブジェクトと配列のプロパティがコピーされない場合、このコピーはシャローコピーと呼ばれます。
ディープコピーとは何ですか?
コピーすると、オブジェクトと配列のプロパティを含む、オブジェクト内のすべてのプロパティがコピーされます。このコピーはディープコピーと呼ばれます。
ディープコピーを実装する方法は?
cloneメソッドをオーバーライドする場合、Objectプロパティとarrayプロパティでcloneメソッドを呼び出すことにより、ディープコピーを実行できます。コピーされたオブジェクトのObjectプロパティは、Cloneableインターフェイスも実装するために必要であり、cloneメソッドはオーバーライドされます。
//Teacher类实现了Cloneable接口,重写了clone方法
public class Teacher implements Cloneable{
private String tname;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
//Student类重写clone方法时,调用了Teacher类的clone方法,实现深拷贝
@Override
protected Student clone() throws CloneNotSupportedException {
Student cloneStudent = (Student) super.clone();
cloneStudent.setTeacher((Teacher) cloneStudent.getTeacher().clone());
return cloneStudent;
}
Studentオブジェクトをコピーし、2つのオブジェクトとオブジェクトのプロパティが等しいかどうかを比較します。
public class cloneObject {
public static void main(String[] args) throws CloneNotSupportedException {
Teacher teacher = new Teacher("罗翔老师");
Student student = new Student("学生1",18,teacher);
System.out.println("clone前的Student对象为:"+student);
Student cloneStudent = student.clone();
System.out.println("clone后的Student对象为:"+cloneStudent);
System.out.println("Student对象与cloneStudent对象是否相等:"+student.equals(cloneStudent));
System.out.println("student对象和cloneStudent对象中的teacher属性是否相等:"+student.getTeacher().equals(cloneStudent.getTeacher()));
//修改student对象中teacher属性的值,观察cloneStudent对象中的teacher属性的值是否会变
student.getTeacher().setTname("张三老师");
System.out.println("cloneStudent对象中teacher属性的值为:"+cloneStudent.getTeacher());
}
}
印刷結果は
clone前的Student对象为:Student{sname='学生1', sage=18, teacher=Teacher{tname='罗翔老师'}}
clone后的Student对象为:Student{sname='学生1', sage=18, teacher=Teacher{tname='罗翔老师'}}
Student对象与cloneStudent对象是否相等:false
student对象和cloneStudent对象中的teacher属性是否相等:false
cloneStudent对象中teacher属性的值为:Teacher{tname='罗翔老师'}
印刷結果は、ディープコピー後の2つのオブジェクトとそれらのプロパティが等しくないことを示しています。
要約する
- コピーとは、元のオブジェクトのプロパティの一部またはすべてを再利用するために、メタオブジェクトに基づいて新しいオブジェクトを作成することです。
- 浅拷贝是拷贝后两个对象地址不相等,但两个对象的部分属性地址相等,新对象并没有拷贝所有的属性,而是复用原对象中的值。
- 深拷贝是拷贝后两个对象不仅地址不相等,两个对象的所有属性地址都不相等。