자바 딥 복사(구현 상의 비교 분석)

11389 단어 c#딥 카피
건물 주 는 asp.net 공 성 사자 로 최근 자바 팀 에 카 메 오로 출연 해 개발 을 돕 고 있 기 때문에 최근 자바 의 기초 지식 에 특히 신경 을 쓰 고 있다.한 대상 을 깊이 복사 해 다른 일 을 해 야 하고 원래 대상 은 원래 상 태 를 유지 해 야 하 는 경우 가 있다.정말 new 가 나 와 서 필드 에 값 을 부여 하고 싶 지 않 습 니 다..................................................................................

나 만 의 이유 인지,아니면 정말 이런 순 반사 로 이 루어 진 깊 은 복사 방식 이 존재 하지 않 는 지...(c\#순 반사 로 이 루어 진 것)
하지만 헛수고 라 고 할 수 는 없 잖 아 요.다른 딥 복사 방식 도 찾 았 습 니 다.(하지만 모든 방식 이 합 리 적 이지 않다 고 생각 합 니 다.c\#방식 이 들 어 왔 기 때 문 일 수도 있 습 니 다.마지막 으로 c\#버 전 순 반사 로 딥 복사 코드 를 붙 였 습 니 다)
방식 1:Cloneable 인터페이스 구현,clone 재 작성 방법
실체 류:하나의 타이어 류,하나의 차량 류,차량 에 타이어 가 포함 되 어 있 습 니 다.

/**   **/
public class Tire implements Cloneable {
  public String color;
  public int radius;
  public Tire(){}
  public Tire(String color, int radius) {
    this.color = color;
    this.radius = radius;
  }

  @Override
  protected Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
}
/**   **/
public class Car implements Cloneable{
  public String name;
  public String color;
  public Tire tire;
  public Car() {}
  public Car(String name, String color, Tire tire) {
    this.name = name;
    this.color = color;
    this.tire = tire;
  }
  public void whistle(){
    System.out.println("  "+this.name+"   ...");
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getColor() {
    return color;
  }
  public void setColor(String color) {
    this.color = color;
  }
  public Tire getTire() {
    return tire;
  }
  public void setTire(Tire tire) {
    this.tire = tire;
  }
  @Override
  protected Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
}

@Test
  public void test() throws CloneNotSupportedException {
    Tire tire = new Tire("black",100);
    Car car = new Car("  ","white",tire);
    Car car_copy = (Car)car.clone();
    System.out.println("car:"+car.hashCode()+" car.tire:"+car.tire.hashCode());
    System.out.println("car_copy:"+car_copy.hashCode()+" car_copy.tire:"+car_copy.tire.hashCode());
    car_copy.color = "blue";
    System.out.println("car_copy:"+car_copy.color+" car:"+car.color);
  }
출력 결과:

car:1223737555 car.tire:906199566
car_copy:542081238 car_copy.tire:906199566
car_copy:blue car:white
결과 적 으로 가능 합 니 다.car 와 carcopy 의 메모리 주 소 는 일치 하지 않 지만,car.tire 와 carcopy.tire 의 메모리 주 소 는 일치 합 니 다."벤츠"차 가 확실히 또 한 대 를 만 들 었 다 는 것 을 설명 하지만 같은 타이어(이런 상황...하하 하)를 사용 합 니 다.좋 습 니 다.즉,tire 의 인용 만 복사 한 것 입 니 다.이것 은 깊이 복사 한 불철저(hashCode()의 값 을 메모리 주소 로 이해 할 수 있 습 니 다)이 라 고 할 수 있 습 니 다.그러면 어떻게 해 야 철저 하고 진정한 깊이 복사 할 수 있 습 니까?
Car 클래스 의 clone 방법 수정:

@Override
  protected Object clone() throws CloneNotSupportedException {
    Car car = (Car)super.clone();
    car.tire = (Tire)car.tire.clone();
    return car;
  }
출력 결과:

car:1223737555 car.tire:906199566
car_copy:542081238 car_copy.tire:1133736492
car_copy:blue car:white
이렇게 해서 최종 적 으로 실현 되 었 습 니 다.그러나 이런 방식 은 프로젝트 에 적합 하지 않 습 니 다.깊이 복사 해 야 하 는 모든 종 류 는 Cloneable 인 터 페 이 스 를 실현 하고 clone 방법 을 덮어 야 합 니 다.다른 종 류 를 인용 할 때 clone 방법 을 수정 해 야 합 니 다.다른 종 류 를 인용 하면 다른 종 류 를 참조 해 야 합 니까?이 건 아니 지..
방식 2:직렬 화 와 반 직렬 화 를 통 해 실현(Serializable 인터페이스 실현)
실체 클래스:첫 번 째 방식 과 유사 합 니 다.Serializable 인 터 페 이 스 를 실현 하고 clone 방법 을 제거 합 니 다.

/**   **/
@SuppressWarnings("serial")
public class Tire implements java.io.Serializable {
  public String color;
  public int radius;
  public Tire(){}
  public Tire(String color, int radius) {
    this.color = color;
    this.radius = radius;
  }
}
/**   **/
@SuppressWarnings("serial")
public class Car implements java.io.Serializable{
  public String name;
  public String color;
  public Tire tire;
  public Car() {}
  public Car(String name, String color, Tire tire) {
    this.name = name;
    this.color = color;
    this.tire = tire;
  }
  public void whistle(){
    System.out.println("  "+this.name+"   ...");
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getColor() {
    return color;
  }
  public void setColor(String color) {
    this.color = color;
  }
  public Tire getTire() {
    return tire;
  }
  public void setTire(Tire tire) {
    this.tire = tire;
  }
}
딥 카피 방법:

@SuppressWarnings("unchecked")
  public static Object deepClone(Object obj)
  {
    Object copyObj = null;
    ObjectOutputStream out = null;
    ObjectInputStream in = null;
    try {
      //    
      ByteArrayOutputStream bufferOut = new ByteArrayOutputStream();
      out = new ObjectOutputStream(bufferOut);

      out.writeObject(obj);

      //     
      ByteArrayInputStream bufferIn = new ByteArrayInputStream(bufferOut.toByteArray());
      in = new ObjectInputStream(bufferIn);
      copyObj = in.readObject();
    } catch (Exception e) {
      e.printStackTrace();
      throw new RuntimeException(e); 
    }finally{
       try{
         if(in != null){
           in.close();
         }
         if(out!=null){
           out.close();
         }
       }catch(IOException e){
         throw new RuntimeException(e);
       }
    }
    return copyObj;
  }
유닛 테스트:

@Test
  public void test() throws CloneNotSupportedException {
    Tire tire = new Tire("black",100);
    Car car = new Car("  ","white",tire);
    Car car_copy = (Car)deepClone(car);
    System.out.println("car:"+car.hashCode()+" car.tire:"+car.tire.hashCode());
    System.out.println("car_copy:"+car_copy.hashCode()+" car_copy.tire:"+car_copy.tire.hashCode());
    car_copy.color = "blue";
    System.out.println("car_copy:"+car_copy.color+" car:"+car.color);
  }
출력 결과:

car:2019524978 car.tire:855703640
car_copy:1407965019 car_copy.tire:545768040
car_copy:blue car:white
결과 집 을 보면 깊 은 복사 가 정확 하 다 는 것 을 알 수 있 지만 각 종 류 는 Serializable 을 실현 해 야 하 는 것 도 적절 하지 않 은 것 같 습 니 다.
깊 은 복사 방법 최적화:이 를 범 형 으로 바 꾸 면 복사 할 필요 가 없다(그래,사실 위의 방법 만큼 좋 은 것 도 없다.)

@SuppressWarnings("unchecked")
  public static <T> T deepClone(T obj)
  {
    T copyObj = null;
    ObjectOutputStream out = null;
    ObjectInputStream in = null;
    try {
      //    
      ByteArrayOutputStream bufferOut = new ByteArrayOutputStream();
      out = new ObjectOutputStream(bufferOut);

      out.writeObject(obj);

      //     
      ByteArrayInputStream bufferIn = new ByteArrayInputStream(bufferOut.toByteArray());
      in = new ObjectInputStream(bufferIn);
      copyObj = (T)in.readObject();
    } catch (Exception e) {
      e.printStackTrace();
      throw new RuntimeException(e); 
    }finally{
       try{
         if(in != null){
           in.close();
         }
         if(out!=null){
           out.close();
         }
       }catch(IOException e){
         throw new RuntimeException(e);
       }
    }
    return copyObj;
  }
직렬 화 와 반 직렬 화 깊 은 복사 와 더 간단 한 실현 방식 이 있 습 니 다.바로 가방 을 안내 해 야 합 니 다(복사 하 는 클래스 도 Serializable 인 터 페 이 스 를 실현 해 야 합 니 다).물론 저 는 클릭->org.apache.comons.lang 을 준비 해 두 었 습 니 다.
딥 복사 방법:코드 한 줄 만...

public Object deepClone(Object obj){
     return org.apache.commons.lang.SerializationUtils.clone((Serializable)obj);
   }
자,자바 의 당분간 은 여기까지 입 니 다.물론 이 두 가지 방식 에 만족 하지 않 습 니 다.
-------------------------------------------------
C\#심 복사 반사 실현
다음 방법 은 c\#의 깊 은 복사,순 반사 실현,어떠한 인터페이스 도 실현 할 필요 가 없습니다.

/// <summary>
    ///     
    /// </summary>
    /// <param name="obj">     </param>
    /// <returns>   </returns>
    private object CopyOjbect(object obj) {
      if (obj == null) {
        return null;
      }
      Object targetDeepCopyObj;
      Type targetType = obj.GetType();
      //    
      if (targetType.IsValueType == true) {
        targetDeepCopyObj = obj;
      }
      //      
      else {
        targetDeepCopyObj = System.Activator.CreateInstance(targetType);  //        
        System.Reflection.MemberInfo[] memberCollection = obj.GetType().GetMembers();

        foreach (System.Reflection.MemberInfo member in memberCollection) {
          //    
          if (member.MemberType == System.Reflection.MemberTypes.Field)
          {
            System.Reflection.FieldInfo field = (System.Reflection.FieldInfo)member;
            Object fieldValue = field.GetValue(obj);
            if (fieldValue is ICloneable)
            {
              field.SetValue(targetDeepCopyObj, (fieldValue as ICloneable).Clone());
            }
            else
            {
              field.SetValue(targetDeepCopyObj, CopyOjbect(fieldValue));
            }

          }//    
          else if (member.MemberType == System.Reflection.MemberTypes.Property) {
            System.Reflection.PropertyInfo myProperty = (System.Reflection.PropertyInfo)member;

            MethodInfo info = myProperty.GetSetMethod(false);
            if (info != null) {
              try {
                object propertyValue = myProperty.GetValue(obj, null);
                if (propertyValue is ICloneable) {
                  myProperty.SetValue(targetDeepCopyObj, (propertyValue as ICloneable).Clone(), null);
                }
                else {
                  myProperty.SetValue(targetDeepCopyObj, CopyOjbect(propertyValue), null);
                }
              }
              catch (System.Exception ex) {

              }
            }
          }
        }
      }
      return targetDeepCopyObj;
    }
이상 의 c\#딥 복사 방식 은 자바 딥 복사(실현 상의 비교 분석)를 완 벽 히 이 기 는 것 이 바로 편집장 이 여러분 에 게 공유 하 는 모든 내용 입 니 다.여러분 께 참고 가 되 고 많은 응원 을 바 랍 니 다.
유닛 테스트:

좋은 웹페이지 즐겨찾기