이 기사는 Java 객체의 얕은 복제와 심층 복제에 대한 자세한 분석을 제공합니다. 이는 특정 참고 가치가 있으므로 도움이 될 수 있습니다.
Object 기본 클래스에는 이전 개체의 복제본을 생성하는 clone이라는 메서드가 있습니다. 복제된 개체는 원본 개체의 복사본입니다. 참조 유형이 존재하기 때문에 복제된 객체에 참조 유형 속성이 있는 경우 심층 복제는 이 속성의 전체 복사본을 만드는 반면 얕은 복제는 이에 대한 참조만 복사합니다. 기인하다. 먼저 쉽게 만들 수 있는 몇 가지 사소한 문제를 살펴보겠습니다.
Cloneable 인터페이스가 아닌 Object 클래스에 복제 방법이 표시 인터페이스가 사용됩니다. 클래스에는 Serialized, Cloneable 및 RandomAccess의 세 가지 일반적인 표시 인터페이스가 있습니다. Cloneable 인터페이스가 구현되지 않으면 clone 메서드가 호출될 때 CloneNotSupportedException이 발생합니다.
Object 클래스의 clone 메서드는 protected로 수정됩니다. 즉, 하위 클래스에서 이 메서드를 재정의하지 않으면 하위 클래스 외부에서 액세스할 수 없습니다. 객체에서 사용 가능 패키지와 해당 패키지가 포함된 하위 클래스에서 액세스할 수 있습니다. 이는 또한 상위 클래스 메서드를 재정의하는 하위 클래스의 권한 한정자가 더 커질 수 있지만 더 작아질 수는 없다는 설명도 확인합니다.
protected native Object clone() throws CloneNotSupportedException;
내부적으로 clone 메서드를 재정의하면 상위 클래스의 clone 메서드만 호출됩니다. 사실 접근 권한을 public으로 변경해도 되지만 그럴 필요는 없습니다. 미래에 상속받는다면 다시 작성하세요. 물론, 얕은 클로닝을 위한 클론 기능일 뿐이고, 딥 클로닝은 수정이 필요합니다.
@Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
속성이 String이고 String도 클래스인 경우 String은 참조 유형인가요? String은 기본 유형처럼 동작합니다. 결론은 String을 변경할 수 없다는 것입니다. 복제 후에는 두 참조가 동일한 String을 가리킵니다. 그러나 둘 중 하나가 수정되면 String의 값은 변경되지 않습니다. 문자열이 생성됩니다. 수정된 참조는 새 문자열을 가리킵니다. 외형은 기본형과 같습니다.
Shallow clone은 User 클래스에 grade 속성 Mark가 포함되어 있어 참조 유형 속성을 완전히 복사할 수 없음을 의미합니다. , etc.,shallow clone 복제 실패의 예
class Mark{ private int chinese; private int math; public Mark(int chinese, int math) { this.chinese = chinese; this.math = math; } public void setChinese(int chinese) { this.chinese = chinese; } public void setMath(int math) { this.math = math; } @Override public String toString() { return "Mark{" + "chinese=" + chinese + ", math=" + math + '}'; } } public class User implements Cloneable{ private String name; private int age; private Mark mark; public User(String name, int age,Mark mark) { this.name = name; this.age = age; this.mark = mark; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", mark=" + mark + '}'; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public static void main(String[] args) throws CloneNotSupportedException { Mark mark = new Mark(100,99); User user = new User("user",22,mark); User userClone = (User) user.clone(); System.out.println("原user:"+user); System.out.println("克隆的user:"+userClone); //修改引用类型的mark属性 user.mark.setMath(60); System.out.println("修改后的原user:"+user); System.out.println("修改后的克隆user:"+userClone); } }
출력 결과는 다음과 같습니다:
원래 사용자: User{name='user', age=22, mark=Mark {chinese=100, math= 99}}
복제 사용자: User{name='user', age=22, mark=Mark{chinese=100, math=99}}
수정된 원래 사용자: 사용자{name= 'user', age=22, mark=Mark{chinese=100, math=60}}
수정된 복제 사용자: User{name='user', age=22, mark=Mark{chinese =100 , math=60}}
사용자 표시가 변경된 후에는 복제된 사용자도 수정되는 것이 분명합니다. 그리고 영향을 받지 않으려면 심층 복제가 필요합니다.
참조 유형을 완전히 복제할 수 없으므로 참조 유형도 다음과 같습니다. 구현됨 Cloneable 인터페이스는 복제 메소드를 다시 작성합니다. User 클래스는 메소드의 중첩 호출인 속성의 복제 메소드를 호출합니다.
class Mark implements Cloneable{ private int chinese; private int math; public Mark(int chinese, int math) { this.chinese = chinese; this.math = math; } public void setChinese(int chinese) { this.chinese = chinese; } public void setMath(int math) { this.math = math; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Mark{" + "chinese=" + chinese + ", math=" + math + '}'; } } public class User implements Cloneable{ private String name; private int age; private Mark mark; public User(String name, int age,Mark mark) { this.name = name; this.age = age; this.mark = mark; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", mark=" + mark + '}'; } @Override protected Object clone() throws CloneNotSupportedException { User user = (User) super.clone(); user.mark = (Mark) this.mark.clone(); return user; } public static void main(String[] args) throws CloneNotSupportedException { Mark mark = new Mark(100,99); User user = new User("user",22,mark); User userClone = (User) user.clone(); System.out.println("原user:"+user); System.out.println("克隆的user:"+userClone); //修改引用类型的mark属性 user.mark.setMath(60); System.out.println("修改后的原user:"+user); System.out.println("修改后的克隆user:"+userClone); } }
출력 결과는 다음과 같습니다. name='user', age=22, mark=Mark{chinese=100, math=99}}
복제 사용자: User{name='user', age=22, mark=Mark{ Chinese=100, math=99}} 수정된 원래 사용자: User{name='user', age=22, mark=Mark{chinese=100, math=60}}
수정 후 복제 사용자: User{ name='user', age=22, mark=Mark{chinese=100, math=99}}
방법 2: 직렬화
import java.io.*; class Mark implements Serializable { private int chinese; private int math; public Mark(int chinese, int math) { this.chinese = chinese; this.math = math; } public void setChinese(int chinese) { this.chinese = chinese; } public void setMath(int math) { this.math = math; } @Override public String toString() { return "Mark{" + "chinese=" + chinese + ", math=" + math + '}'; } } public class User implements Serializable{ private String name; private int age; private Mark mark; public User(String name, int age,Mark mark) { this.name = name; this.age = age; this.mark = mark; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", mark=" + mark + '}'; } public static void main(String[] args) throws IOException, ClassNotFoundException { Mark mark = new Mark(100,99); User user = new User("user",22,mark); ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(user);//序列化 ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); User userClone = (User) oi.readObject();//反序列化 System.out.println("原user:"+user); System.out.println("克隆的user:"+userClone); user.mark.setMath(59); System.out.println("修改后的原user:"+user); System.out.println("修改后的克隆user:"+userClone); } }
출력 결과:
원래 사용자: User{name='user', age=22, mark= Mark{chinese=100, math=99}}
복제 사용자: User{name='user', age=22, mark=Mark{chinese=100, math=99}} 수정 후 원래 사용자: User{name='user', age=22, mark=Mark{chinese=100, math=60}}
수정된 복제 사용자: User{name='user', age=22 , mark =Mark{중국어=100, 수학=99}}
배열 속성으로 복제
import java.io.*; import java.util.Arrays; public class User implements Serializable{ private String name; private int age; private int[] arr; public User(String name, int age, int[] arr) { this.name = name; this.age = age; this.arr = arr; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", arr=" + Arrays.toString(arr) + '}'; } public static void main(String[] args) throws IOException, ClassNotFoundException { int[] arr = {1,2,3,4,5,6}; User user = new User("user",22,arr); ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(user);//序列化 ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); User userClone = (User) oi.readObject();//反序列化 System.out.println("原user:"+user); System.out.println("克隆的user:"+userClone); user.arr[1] = 9; System.out.println("修改后的原user:"+user); System.out.println("修改后的克隆user:"+userClone); } }
위 내용은 Java 개체의 얕은 복제 및 심층 복제에 대한 자세한 분석(예제 포함)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!