얕은 복사(Shallow Copy): 객체의 필드를 복사하지만, 필드가 참조하는 객체는 복사하지 않습니다. 즉, 원본 객체와 복사된 객체가 동일한 객체를 참조!
'주소 값'을 복사한다는 의미
복사는 동일한 주소를 바라보기때문에 복사한 곳에서 값 변경이 일어나면 바뀜
public static void main(String[] args) {
MyObject original = new MyObject(5);
MyObject shallowCopy = original; // 얕은 복사
shallowCopy.data = 10;
System.out.println(original.data); // 출력: 10
}
static class MyObject {
int data;
MyObject(int data) {
this.data = data;
}
}
}
// 10
그림설명
결국 얕은 복사는 heap영역의 참조값을 동일하게 바라보고 있음.
'실제 값'을 새로운 메모리 공간에 복사하는 것을 의미
깊은 복사(Deep Copy): 객체의 필드를 복사하고, 필드가 참조하는 객체도 복사
원본 객체와 복사된 객체는 완전히 독립적
독립적인 객체 그래서 복사된 값을 바꿔도 변함이없다.
public class DeepCopy {
public static void main(String[] args) {
MyObject original = new MyObject(5);
MyObject deepCopy = original.deepCopy(); // 깊은 복사
deepCopy.data = 10;
System.out.println(original.data); // 출력: 5
}
static class MyObject {
int data;
MyObject(int data) {
this.data = data;
}
MyObject deepCopy() {
return new MyObject(this.data);
}
}
}
public class CopyObject implements Cloneable {
private String name;
private int age;
public CopyObject() {
}
public CopyObject(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public CopyObject clone() throws CloneNotSupportedException {
return (CopyObject) super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class Clone {
public static void main(String[] args) throws CloneNotSupportedException {
CopyObject original = new CopyObject("superkkj", 22);
CopyObject copy = original.clone();
copy.setName("gkj");
System.out.println(original.getName()); // superkkj
System.out.println(copy.getName()); // gkj
}
}
클래스가 Object 클래스의 clone() 메소드를 사용하여 필드별 복사(field-for-field copy)를 수행할 수 있음을 나타내는 역할
마커 인터페이스: Cloneable은 마커 인터페이스로, 이 인터페이스를 구현한다는 것은 해당 클래스가 복제 가능함을 나타냅니다.
복사 허용: 클래스가 Cloneable을 구현하면, Object 클래스의 clone() 메소드를 호출할 때, CloneNotSupportedException 예외가 발생하지 않습니다.
이런 설명..
메소드 오버라이딩: Cloneable 인터페이스를 구현하는 클래스는 일반적으로 Object의 clone() 메소드를 public으로 오버라이딩해야함
object의 clone() 메소드는 기본적으로 protected이기 때문에, 이를 오버라이딩하지 않으면 다른 패키지나 클래스에서 접근할 수 없습니다.
Object의 clone() 메소드는 기본적으로 얕은 복사를 수행합니다. 따라서 깊은 복사를 원한다면 clone() 메소드를 오버라이딩하여 직접 구현해야 한다!
CloneNotSupportedException 처리도 해줘야 됨.
뭐지 근대 위에코드는 얕은복사같은데 왜 깊은복사가 일어나지????
package com.dev.study;
import java.util.ArrayList;
import java.util.List;
public class TestClone implements Cloneable {
private String name;
private int age;
private List<String> hobbies;
public TestClone(String name, int age, List<String> hobbies) {
this.name = name;
this.age = age;
this.hobbies = hobbies;
}
@Override
public TestClone clone() throws CloneNotSupportedException {
return (TestClone) super.clone();
}
// Getter와 Setter 메서드들
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
public static void main(String[] args) throws CloneNotSupportedException {
List<String> hobbies = new ArrayList<>();
hobbies.add("Reading");
hobbies.add("Gaming");
TestClone original = new TestClone("superkkj", 22, hobbies);
TestClone copy = original.clone();
// 복사된 객체의 취미 목록 변경
copy.getHobbies().add("Swimming");
copy.setAge(30);
copy.setName("copy");
System.out.println("Original Name: " + original.getName()); // superkkj
System.out.println("Copy Name: " + copy.getName()); // copy
System.out.println("original age: " + original.getAge()); // 22
System.out.println("Copy age: " + copy.getAge()); // 30
System.out.println("Original Hobbies: " + original.getHobbies()); // [Reading, Gaming, Swimming]
System.out.println("Copy Hobbies: " + copy.getHobbies()); // [Reading, Gaming, Swimming]
}
int , String은 깊은복사
리스트는 얕은복사.. 왜 ?
설명에 의하면 기본 타입은 값에 의한 복사가 이루어지고
String은 불변 타입 객체가 생성되고 참조가 다시 갱신된다 (새로운 문자열 할당시)
그래서 깊은 복사처럼 보임
참조형? 메모리 주소값 가지니까, 실제 객체의 위치.
얕은 복사가 이루어질때 주소값만 복사되니 동일한 데이터 공유,, 아하..
/* 복사 생성자 */
public CopyObject(CopyObject original) {
this.name = original.name;
this.age = original.age;
}
/* 복사 팩터리 */
public static CopyObject copy(CopyObject original) {
CopyObject copy = new CopyObject();
copy.name = original.name;
copy.age = original.age;
return copy;
}
공변성(Covariance): 하위 타입의 객체를 상위 타입 객체로 대체할 수 있는 속성입니다. 예를 들어, Apple이 Fruit의 하위 타입일 때, Fruit 타입의 참조 변수가 Apple 객체를 참조할 수 있는 것을 의미합니다.
자식이 부모를 대체?
반공변성(Contravariance): 상위 타입의 객체를 하위 타입 객체로 대체할 수 있는 속성입니다. 이는 주로 제네릭 타입에서 볼 수 있으며, 예를 들어, Fruit가 Apple의 상위 타입일 때, Apple 타입의 참조 변수로 Fruit 타입 객체를 참조하는 것은 불가능하지만, 반대로 Fruit 타입의 참조 변수로 Apple 타입 객체를 참조하는 것은 가능합니다.
부모가 자식을 대체 흐음.