728x90
clone() _ 얕은 복사, 깊은 복사
- clone()
- 인스턴스변수의 값만 복사하기 때문에 참조타입의 인스턴스 변수가 있는 클래스는 완전한 인스턴스 복제가 일어나지 않는다.
- 참조타입의 인스턴스 변수: 객체에 iv들이 존재하는데 iv 값이 다른 객체 주소를 가리키는 상황.
- 완전한 복제가 안된다는 의미: 객체까지는 복사가 됬는데 객체 내부의 iv가 가리기는 다른 객체는 서로 공유하는 상황
- 참조타입의 인스턴스 변수: 객체에 iv들이 존재하는데 iv 값이 다른 객체 주소를 가리키는 상황.
- 이와 같은 clone을 얕은 복사라고 한다. -> 서로 공유하는 객체가 존재하기 때문
- clone() 사용 방법
clone의 얕은 복사로 인해 원본 객체에 영향을 끼치기 때문에 원본 보호 목적으로 특정 조건을 허용해야 clone()을 사용할 수 있도록 했다.- implements Cloneable : interface 구현
- 접근제어자를 public으로 변경
- try-catch문을 통해 반드시 예외 처리 필요
- implements Cloneable : interface 구현
- clone 내부의 작동이 궁금하다면 아래 블로그를 참고
https://vixxcode.tistory.com/204#--%--%--Target
- 인스턴스변수의 값만 복사하기 때문에 참조타입의 인스턴스 변수가 있는 클래스는 완전한 인스턴스 복제가 일어나지 않는다.
class Point implements Cloneable {
int x, y;
Point(int x, int y){
this.x = x;
this.y = y;
}
public String toString() {
return "x=" + x + ", y=" + y;
}
public Object clone(){
Object obj = null;
try {
obj = super.clone();
// clone의 내부 작동을 사용하기 위해서는 조상 Object의 clone으로 갈 수 밖에 없다.
} catch (CloneNotSupportedException e) {}
return obj;
}
}
class CloneEx1 {
public static void main(String[] args){
Point original = new Point(3,5);
Point copy = (Point)original.clone(); // clone 후 새 객체 생성
System.out.println(original);
System.out.println(copy);
}
}
- 얕은 복사 vs 깊은 복사 <면접 질문>
- 얕은 복사
- 정의 : 원본과 복제본이 같은 객체를 공유하는 복사
- 장점 : 복사 속도가 빠르다.
- 단점 : 원본을 회손하므로 변경에 유리하지 않다.
- 사용 : 읽기만 할 때
- 깊은 복사
- 정의 : 원본이 참조하고 있는 객체까지 복제하는 것
- 장점 : 완벽한 복사본을 가지므로 원본을 회손하지 않는다. == 변경에 유리하다.
- 단점 : 복사 속도가 느리다. 만들기 복잡하다.
- 사용 : 읽고 쓰기를 할 때
- 코드와 그림으로 보기
- p, r 은 얕은복사와 깊은 복사 둘다 복사 완료
- p가 가진 객체 주소는 깊은 복사만 복사 완료
- 얕은 복사
public class Practice {
public static void main(String[] args) {
Circle c1 = new Circle(new Point(1, 1), 2.0);
Circle c2 = c1.shallowCopy();
Circle c3 = c1.deepCopy();
System.out.println("c1 = " + c1);
System.out.println("c2 = " + c2);
System.out.println("c3 = " + c3);
c2.p.x =1234323;
c2.p.y =3413542;
c1.r = 34.23423;
System.out.println("c1 = " + c1);
System.out.println("c2 = " + c2);
System.out.println("c3 = " + c3);
}
}
class Circle implements Cloneable{
Point p;
double r;
Circle(Point p, double r) {
this.p = p;
this.r = r;
}
// 얕은 복사
public Circle shallowCopy(){
Object obj = null;
try {
obj = super.clone();
} catch (CloneNotSupportedException e){}
return (Circle) obj;
}
// 깊은 복사
public Circle deepCopy(){
Object obj = null;
try {
obj = super.clone();
} catch (CloneNotSupportedException e) {};
Circle c = (Circle) obj;
c.p = new Point(this.p.x, this.p.y); // c.p가 가리키는 Point 객체주소를 새로운 객체주소로 변경해줌
return c;
}
public String toString() {
return "[p=" + p + ", r=" + r + "]";
}
}
class Point{
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return "(" + x + ", " + y + ")";
}
}
- 공변 반환타입 (Covariant return type)
- 오버라이딩할 때 조상 메서드의 반환타입을 자손 클래스의 타입으로 변경을 허용
- 변성의 종류
- 자바의 변성 - 공변/무공변/반공변, 사용지점 변성과 선언 지점 변성 - https://scshim.tistory.com/531
- 현재는 공변이 핵심이 아니므로 이정도로 넘어간다.
- 사용 목적
- 형변환을 줄이는 것이 의미없는 코드길이를 단축화 할 수 있다.
- 참고 - 배열
- 배열class는 Cloneable과 serializable 인터페이스가 구현되어 있다. -> Object member 모두 상속
- clone을 할 때도 공변을 통한 type변환이 이미 이루어졌기 때문에 형변환을 할 필요가 없다.
- 결론 배열 복사 방법이 3가지가 존재
- for문으로 노가다
- clone()으로 배열 복사
- Sytem.arraycopy()로 배열 복사
- 배열class는 Cloneable과 serializable 인터페이스가 구현되어 있다. -> Object member 모두 상속