Java로 객체를 어떻게 복사합니까?



Answers

기본 : 자바에서 객체 복사.

두 객체 obj1containedObj2 를 포함하는 객체 obj1 가정 해보자.

얕은 복사 :
얕은 복사는 동일한 클래스의 새 instance 를 만들고 모든 필드를 새 인스턴스에 복사 한 다음 반환합니다. Object 클래스clone 메서드를 제공하고 얕은 복사를 지원합니다.

딥 복사 :
전체 복사본 은 개체가 참조 할 개체와 함께 복사 될 때 발생합니다. 아래 이미지는 딥 복사가 수행 된 후 obj1 을 보여줍니다. obj1 이 복사되었을 뿐만 아니라 그 안에 포함 된 객체도 복사됩니다. Java Object Serialization 을 사용하여 전체 복사본을 만들 수 있습니다. 불행히도이 접근법에는 몇 가지 문제점이 있습니다 ( 자세한 예제 ).

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

  1. public clone() 메서드를 가지고있는 객체가 있지만 컴파일 타임에 객체의 유형을 모르는 경우 문제가 발생합니다. Java에는 Cloneable 이라는 Cloneable 있습니다. 실제로 객체를 Cloneable 으로 만들려면이 인터페이스를 구현해야합니다. Object.clone보호 되어 있으므로 액세스하기 위해서는 public 메서드로 재정의 해야합니다.
  2. 또 다른 문제는 복잡한 객체완전한 복사 를 시도 할 때 발생 합니다 . 모든 멤버 객체 변수의 clone() 메소드가 딥 복사를한다고 가정합니다. 이것은 너무 위험합니다. 모든 클래스의 코드를 제어해야합니다.

예를 들어, org.apache.commons.lang.SerializationUtils 는 직렬화 ( Source )를 사용하여 딥 클론을위한 메소드를 갖습니다. Bean을 복제해야한다면 org.apache.commons.beanutils ( Source )에 몇 가지 유틸리티 메소드가있다.

  • cloneBean 은 빈 클래스 자체가 Cloneable을 구현하지 않더라도 사용 가능한 속성 getter 및 setter를 기반으로 빈을 복제합니다.
  • copyProperties 는 속성 이름이 같은 모든 경우에 대해 원두 bean에서 대상 bean으로 속성 값을 복사합니다.
Question

아래 코드를 살펴보십시오.

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'

그래서 나는 dum 을 복사해서 dumtwo 영향을주지 않으면 서 dumdumtwo dumtwo . 그러나 위의 코드는 그렇게하지 않습니다. 내가 dumtwo 뭔가를 바꿀 dumtwo 똑같은 변화가 일어나고 있습니다.

dumtwo = dum 이라고 dumtwo = dum Java는 참조 만 복사합니다. 그럼, dum 의 새로운 복사본을 만들고 그것을 dumtwo 할당하는 방법이 dumtwo ?







이것도 작동합니다. 모델 가정

class UserAccount{
   public int id;
   public String name;
}

먼저 앱> gradle & sync에 compile 'com.google.code.gson:gson:2.8.1' 을 추가하십시오. 그때

Gson gson = new Gson();
updateUser = gson.fromJson(gson.toJson(mUser),UserAccount.class);

액세스 한정자 다음에 transient 키워드를 사용하여 필드를 사용하여 제외 할 수 있습니다.

참고 : 이것은 나쁜 습관입니다. 또한 Cloneable 또는 JavaSerialization 을 사용하지 않는 것이 좋습니다. 느리고 깨졌습니다. 최고의 성능을위한 복사 생성자를 작성하십시오.

좋아하는 것

class UserAccount{
        public int id;
        public String name;
        //empty constructor
        public UserAccount(){}
        //parameterize constructor
        public UserAccount(int id, String name) {
            this.id = id;
            this.name = name;
        }

        //copy constructor
        public UserAccount(UserAccount in){
            this(in.id,in.name);
        }
    }

90000 반복 테스트 통계 :
Line UserAccount clone = gson.fromJson(gson.toJson(aO), UserAccount.class); 808ms 걸린다.

Line UserAccount clone = new UserAccount(aO); 1ms 미만 걸린다.

결론 : 사장님이 미쳐서 스피드를 좋아하시면 gson을 사용하십시오. 품질을 선호하는 경우 두 번째 복사본 생성자를 사용하십시오.

Android Studio에서 복사 생성자 코드 생성기 플러그인 을 사용할 수도 있습니다.




복사하고자하는 객체를 전달하고 원하는 객체를 가져옵니다.

private Object copyObject(Object objSource) {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(objSource);
            oos.flush();
            oos.close();
            bos.close();
            byte[] byteData = bos.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
            try {
                objDest = new ObjectInputStream(bais).readObject();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return objDest;

    }

이제 objDest를 desigered 객체로 파싱합니다.

해피 코딩




class DB {
  private String dummy;

  public DB(DB one) {
    this.dummy = one.dummy; 
  }
}









패키지에서 import org.apache.commons.lang.SerializationUtils; 방법이 있습니다.

SerializationUtils.clone(Object);

예:

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



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;
}
}



주석을 소스 파일에 추가 할 수있는 경우이 주석 처리기 또는 코드 생성기를 사용할 수 있습니다.

import net.zerobuilder.BeanBuilder

@BeanBuilder
public class DummyBean { 
  // bean stuff
}

DummyBeanBuilders 클래스가 생성되어, 수동으로 수행하는 것과 같은 방법으로 얕은 복사본을 만드는 정적 메서드 인 dummyBeanUpdater 가 있습니다.

DummyBean bean = new DummyBean();
// Call some setters ...
// Now make a copy
DummyBean copy = DummyBeanBuilders.dummyBeanUpdater(bean).done();



Related