[java] Java에서 객체를 어떻게 복사합니까?

아래 코드를 고려하십시오.

DummyBean dum = new DummyBean();
dum.setDummy("foo");
System.out.println(dum.getDummy()); // prints 'foo'

DummyBean dumtwo = dum;
System.out.println(dumtwo.getDummy()); // prints 'foo'

dum.setDummy("bar");
System.out.println(dumtwo.getDummy()); // prints 'bar' but it should print 'foo'

그래서, 나는 복사 할 dumdumtwo변화 dum에 영향을주지 않고 dumtwo. 그러나 위의 코드는 그렇게하지 않습니다. 에서 무언가를 변경 dum하면 동일한 변화가 발생 dumtwo합니다.

내가 말할 때 dumtwo = dumJava는 참조 만 복사 한다고 생각 합니다 . 따라서 새로운 사본을 만들어 dum할당 할 수있는 방법이 dumtwo있습니까?



답변

복사 생성자를 만듭니다.

class DummyBean {
  private String dummy;

  public DummyBean(DummyBean another) {
    this.dummy = another.dummy; // you can access  
  }
}

모든 객체에는 객체를 복사하는 데 사용할 수있는 복제 방법도 있지만 사용하지는 마십시오. 클래스를 생성하고 부적절한 클론 메소드를 수행하는 것은 너무 쉬운 방법입니다. 그렇게하려면 적어도 Joshua Bloch가 Effective Java 에서 그것에 대해 말한 내용을 읽으십시오 .


답변

기본 : Java에서 객체 복사.

우리는 객체 – 가정하자 obj1, 그 두 개체가 포함되어 containedObj1containedObj2을 .
여기에 이미지 설명을 입력하십시오

얕은 복사 :
얕은 복사 instance는 동일한 클래스 의 새 클래스를 만들고 모든 필드를 새 인스턴스에 복사하여 반환합니다. Object 클래스clone메서드를 제공하고 단순 복사를 지원합니다.
여기에 이미지 설명을 입력하십시오

딥 카피 : 딥 카피 는 객체를 참조하는 객체와 함께 객체를 복사
할 때 발생합니다 . 아래 이미지는 깊은 복사가 수행 된 후의 모습 입니다. 있다뿐만 아니라 복사 ,하지만 그 안에 포함 된 개체가 아니라 복사 한. 딥 카피를 만드는 데 사용할 수 있습니다 . 불행히도,이 접근 방식에는 몇 가지 문제가 있습니다 ( 자세한 예 ).obj1obj1Java Object Serialization
여기에 이미지 설명을 입력하십시오

가능한 문제 :
clone 올바르게 구현하기가 까다 롭습니다. 방어 복사 , 복사 생성자 (@egaga 회신) 또는 정적 팩토리 메소드
를 사용하는 것이 좋습니다 .

  1. 객체가 있고 공개 clone()메소드가 있지만 컴파일 타임에 객체의 유형을 모르는 경우 문제가 있습니다. Java에는라는 인터페이스가 Cloneable있습니다. 실제로 객체를 만들려면이 인터페이스를 구현해야합니다 Cloneable. Object.cloneis protected 이므로 액세스하려면 공개 메소드로 덮어 써야 합니다.
  2. 우리가하려고 할 때 또 다른 문제가 발생 깊은 복사 (A)의 복잡한 객체를 . clone()모든 멤버 객체 변수 의 메소드도 딥 카피를 수행 한다고 가정하면 너무 가정이 위험합니다. 모든 클래스에서 코드를 제어해야합니다.

예를 들어 org.apache.commons.lang.SerializationUtils 에는 serialization ( Source )을 사용하는 딥 클론 방법이 있습니다 . Bean을 복제해야하는 경우 org.apache.commons.beanutils ( Source ) 에 몇 가지 유틸리티 메소드가 있습니다.

  • cloneBean Bean 클래스 자체가 Cloneable을 구현하지 않더라도 사용 가능한 특성 getter 및 setter를 기반으로 Bean을 복제합니다.
  • copyProperties 등록 정보 이름이 동일한 모든 경우에 대해 원점 Bean에서 대상 Bean으로 등록 정보 값을 복사합니다.

답변

패키지 import org.apache.commons.lang.SerializationUtils;에는 다음과 같은 방법이 있습니다.

SerializationUtils.clone(Object);

예:

this.myObjectCloned = SerializationUtils.clone(this.object);


답변

다음과 같이 따르십시오.

public class Deletable implements Cloneable{

    private String str;
    public Deletable(){
    }
    public void setStr(String str){
        this.str = str;
    }
    public void display(){
        System.out.println("The String is "+str);
    }
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

다른 객체를 얻으려면 어디에서나 간단하게 복제를 수행하십시오. 예 :

Deletable del = new Deletable();
Deletable delTemp = (Deletable ) del.clone(); // this line will return you an independent
                                 // object, the changes made to this object will
                                 // not be reflected to other object


답변

Reflection API 사용에 대한 답변이없는 이유는 무엇입니까?

private static Object cloneObject(Object obj){
        try{
            Object clone = obj.getClass().newInstance();
            for (Field field : obj.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                field.set(clone, field.get(obj));
            }
            return clone;
        }catch(Exception e){
            return null;
        }
    }

정말 간단합니다.

편집 : 재귀를 통해 자식 개체 포함

private static Object cloneObject(Object obj){
        try{
            Object clone = obj.getClass().newInstance();
            for (Field field : obj.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                if(field.get(obj) == null || Modifier.isFinal(field.getModifiers())){
                    continue;
                }
                if(field.getType().isPrimitive() || field.getType().equals(String.class)
                        || field.getType().getSuperclass().equals(Number.class)
                        || field.getType().equals(Boolean.class)){
                    field.set(clone, field.get(obj));
                }else{
                    Object childObj = field.get(obj);
                    if(childObj == obj){
                        field.set(clone, clone);
                    }else{
                        field.set(clone, cloneObject(field.get(obj)));
                    }
                }
            }
            return clone;
        }catch(Exception e){
            return null;
        }
    }


답변

Google의 JSON 라이브러리를 사용하여 직렬화 한 다음 직렬화 된 객체의 새 인스턴스를 만듭니다. 몇 가지 제한 사항으로 딥 카피를 수행합니다.

  • 재귀 참조는있을 수 없습니다

  • 이종 유형의 배열을 복사하지 않습니다.

  • 배열과 목록을 입력해야합니다. 그렇지 않으면 인스턴스화 할 클래스를 찾을 수 없습니다

  • 자신을 선언하는 클래스에서 문자열을 캡슐화해야 할 수도 있습니다.

또한이 클래스를 사용하여 사용자 기본 설정, 창 및 런타임시 다시로드하지 않을 내용을 저장합니다. 사용하기 쉽고 효과적입니다.

import com.google.gson.*;

public class SerialUtils {

//___________________________________________________________________________________

public static String serializeObject(Object o) {
    Gson gson = new Gson();
    String serializedObject = gson.toJson(o);
    return serializedObject;
}
//___________________________________________________________________________________

public static Object unserializeObject(String s, Object o){
    Gson gson = new Gson();
    Object object = gson.fromJson(s, o.getClass());
    return object;
}
       //___________________________________________________________________________________
public static Object cloneObject(Object o){
    String s = serializeObject(o);
    Object object = unserializeObject(s,o);
    return object;
}
}


답변

예, 객체를 참조하고 있습니다. 구현 된 객체를 복제 할 수 있습니다 Cloneable.

객체 복사에 대한이 위키 기사를 확인하십시오.

여기를 참조하십시오 : 객체 복사