Clone (); 깊은 복사 ,얇은 복사

2022. 12. 3. 17:22카테고리 없음

 "어떤 객체가 있을때 내가 그 객체와 똑같은 것이 필요할때 사용한다"

 

 

구현방법

  1.  인터페이스  Cloneable 구현 해야 한다  . 실제 Cloneable 클래스가 면 내용이 비어있지만 여기서 의미하는 것은  복제가능한지 아닌지 여부만이다
  2. 접근패키지 ( clone(); 함수는 protected로 되어있어 같은 패키지 혹은 상속 에서만 사용이 가능하다) 그래서  구현시 오버라이딩하여 public으로 바꿔준 후 구현 가능하다.

 

package main;

class Student implements Cloneable {//복제 가능한지 여부 
	String name;
	Student(String name){
		this.name = name;
		
		
	}
	//상속을 받아서  리턴을 할때는 오브젝트 클레스에 clone을 호출하면된다 .
	public Object clone() throws CloneNotSupportedException{//clone하는 과정에서 에러 발생시 사용자에게 위임한다.
		return super.clone();
		
	}
	
}
	
	 class ObjectDemo{
		
		public static   void main(String[] args)  {
			Student s1 = new Student("egoing");
			try {
				Student s2= (Student)s1.clone();
				System.out.println(s1.name);
				System.out.println(s2.name);
			} catch (CloneNotSupportedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
		}
		
	}

결과:

egoing
egoing

 

 

clone()메소드의 오버라이딩 ,사용예제 2

package main3;

 class Point implements Cloneable {//클래스 작성자가 복제를 허용한다.

	int x,y;
	
	Point(int x, int y){
		
		this.x=x;
		this.y=y;
		
		
	}
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return "x:" +x+",y:"+y;
	}
	
	@Override
	public Object clone() {//Object로 리턴이 된다 
		
		Object obj = null;
		
		try {
			obj = super.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			
		}
		return obj;//return타입을 point타입으로 형변환 가능 (Point) obj;
	
	}
	
}


  class CloneTest{
	
	public static void main(String[] args) {
		Point original = new Point(3, 5);
		Point copy =  (Point) original.clone();// Object로 리턴이 되서 메소드 사용시 형변환을 시켜야 한다.
		
		System.out.println(original);
		
		System.out.println(copy);//복사 객체 
		
	}
	
}
x:3,y:5
x:3,y:5

공변 반환 타입 :

point copy = (Point)original.clone(); -> Point copy = original.clone();

 

 

얇은 복사와 깊은 복사 

Clone()으로 복제하는 경우 원본과 복제본이 객체를 공유하므로 완전한 복제라고 보기 어렵다.

이러한 복제(복사)를 얕은 복사 (Shallow copy) 라고 하며 원본을 변경하면 복사본도 영향을 받는다.

깊은 복사 (deep copy)는 원본이 참조하고 있는 객체까지 복제하는 것을 말하고 서로 다른 객체를 참조하기 때문에 원본의 변경이 복사본에 영향을 미치지 않는다.

 

package main8;

public 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) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return (Circle)obj;
		//object 클래스의 clone()은 원본 객체가 가지고 있는 값만 그래도 복사 
		
		
	}
	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);
			
			return c;
			//clone()을 이용하여 복제까지 한 후에 Circle의 멤버 변수 p에게 새로운 인스턴스를 만들어 
		//참조하게 했다, 원본이 참조하고 있는 객체까지 복사한다.
		
		}
	//toString오버라이딩
		public String toString(){
			
			return "p=" +p+"/r="+r;
		}
	
}

class Point{
	
	int x,y;
	
	Point(int x, int y){
		
		this.x=x;
		this.y=y;
		
	}
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return "("+x+","+y+")";
	}
	
	
}


 class ShallowDeepCopy{
	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);
		
		c1.p.x=9;
		c1.p.y=9;
		System.out.println("c1의 변경 후");
		System.out.println("c1:" +c1);
		System.out.println("c2:" +c2);
		System.out.println("c3:" +c3);
		
	}
	
	
	
	
}
c1:p=(1,1)/r=2.0
c2:p=(1,1)/r=2.0
c3:p=(1,1)/r=2.0
c1의 변경 후
c1:p=(9,9)/r=2.0
c2:p=(9,9)/r=2.0
c3:p=(1,1)/r=2.0

얇은 복사 :

단순히 object클래스의 clone()을 호출할 뿐이다.

object클래스의 clone()은 원본 객체가 가지고 있는 값만 그대로 복사한다. 즉 얕은 복사를 한다.

깊은 복사:

deepCopy()는 shallowCopy()와 마찬가지로 일단 clone()을 이용하여 복제까지 한 후에 Circle의 멤버 변수 p에게 새로운 인스턴스를 만들어 참조하게 하였다. 원본이 참조하고 있는 객체까지 복사한 것이다.

 

#추가

int num1 =1;
int num2 = num1;/num 2에는 1이라는 값이 들어간다.

num2=2;

System.out.println(num1,num2)

깊은복사 ( 원시타입)

1
2

얕은복사(객체타입)

package main8;

class lame{
	
	String name="미영";
	String subscriber="3000";
	
	
}




public class test55 {
	public static void main(String[]args) {
		
		lame me = new lame();
		
		lame mecopy = me;
		
		mecopy.subscriber="1000";
		
		System.out.println(me.name +me.subscriber);
		System.out.println(mecopy.name+mecopy.subscriber);

	}
	
}
미영1000
미영1000

결론:  deep copy가 일어나면 비효율적일수가 있다 100개를 다 카피하면 시간이 오래 걸리기에  객체에서는

shallow copy를 사용하는 것이 효율적이다.