java - 깊은 - 자바 인스턴스 복사




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

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

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 ?


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

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

다음과 같이하면됩니다.

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


복사 생성자를 만듭니다.

class DummyBean {
  private String dummy;

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

모든 객체에는 객체를 복사하는 데 사용할 수있는 복제 메소드가 있지만 사용하지는 않습니다. 클래스를 만들고 부적절한 복제 방법을 만드는 것은 너무 쉽습니다. 만약 당신이 그렇게하려고한다면, Joshua Bloch이 Effective Java 에서 그것에 대해 말하고있는 것을 적어도 읽으십시오.


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

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 를 원하는 객체로 파싱합니다.

해피 코딩!



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

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에서 복사 생성자 코드 생성기 플러그인 을 사용할 수도 있습니다.


클래스에 CloneableCloneable 코드 추가

public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

clonedObject = (YourClass) yourClassObject.clone();


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

SerializationUtils.clone(Object);

예:

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

Cloneable 을 구현하고 clone() 메서드를 사용할 수 있습니다. 그러나 복제 방법을 사용하는 경우 표준에 따라 항상 Objectpublic Object clone() 메서드를 재정의해야합니다.


Cloneable 인터페이스를 구현하고 clone() 메서드를 재정의해야하는 Deep Cloning이 답입니다.

public class DummyBean implements Cloneable {

   private String dummy;

   public void setDummy(String dummy) {
      this.dummy = dummy;
   }

   public String getDummy() {
      return dummy;
   }

   @Override
   public Object clone() throws CloneNotSupportedException {
      DummyBean cloned = (DummyBean)super.clone();
      cloned.setDummy(cloned.getDummy());
      // the above is applicable in case of primitive member types, 
      // however, in case of non primitive types
      // cloned.setNonPrimitiveType(cloned.getNonPrimitiveType().clone());
      return cloned;
   }
}

DummyBean dumtwo = dum.clone(); 처럼 호출 할 것입니다. DummyBean dumtwo = dum.clone();


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

두 객체 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으로 속성 값을 복사합니다.

class DB {
  private String dummy;

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






clone