1. 程式人生 > >Java物件的快速複製的幾種方式

Java物件的快速複製的幾種方式

淺拷貝、深度複製、BeanUtils.copyProperties()

物件的克隆是指建立一個新的物件,且新的物件的狀態與原始物件的狀態相同。當對克隆的新物件進行修改時,不會影響原始物件的狀態。

註釋:clone()是object類的protected 方法,只有類的物件自己可以克隆自己

因此,必須實現cloneable接口才可以使用obj.clone()方法,典型的方式,如下

//淺拷貝
class CloneClass implements Cloneable{ 
 public int a; 
 public Object clone(){ 
  CloneClass o = null; 
  try{ 
   o = (CloneClass)super.clone(); 
  }catch(CloneNotSupportedException e){ 
   e.printStackTrace(); 
  } 
  return o; 
 } 
}
//深度拷貝
class CloneClass implements Cloneable{ 
 public int a; 
  public Class1 t;

  public CloneClass (int a,Class1 t) {
        this.a = a;
        this.t = t;
  }


 public Object clone(){ 
  CloneClass o = null; 
  try{ 
   o = (CloneClass)super.clone(); 
      o.test = (Class1)t.clone();
  }catch(CloneNotSupportedException e){ 
   e.printStackTrace(); 
  } 
  return o; 
 } 
}
//Class1 也必須實現Cloneable介面
class Class1 implements Cloneable{ 
    public Object clone(){ 
       Class1 o = null; 
       try{ 
         o = (Class1 )super.clone(); 
       }catch(CloneNotSupportedException e){ 
         e.printStackTrace(); 
       } 
       return o; 
 } 
}

一、淺拷貝clone()

如果物件中的所有資料域都是數值或者基本型別,使用clone()即可滿足需求,如:

Person p = new Person();

Person p1 = p.clone();

這樣p和p1分別指向不同的物件。

二、深度拷貝

如果在物件中包含子物件的引用,拷貝的結果是使得兩個域引用同一個物件,預設的拷貝是淺拷貝,沒有拷貝包含在物件中的內部物件。

如果子物件是不可變的,如String,這沒有什麼問題;如果物件是可變的,必須重新定義clone方法;

三、序列化可克隆(深拷貝)

/*
 * 為克隆使用序列化,
 * 直接將物件序列化到輸出流中,然後將其讀回,這樣產生的新物件是對現有物件的一個深拷貝
 * 在此過程中,不必將物件寫出到檔案,可以用ByteArrayOutPutStream將資料儲存到位元組陣列中
 * 
 * 這個方法很靈巧,它通常會比顯示地構建新物件並複製或克隆資料域的克隆方法慢得多
 */
public class SerialCloneTest
{  
   public static void main(String[] args)
   {  
      Employee harry = new Employee("Harry Hacker", 35000);
      // clone harry
      Employee harry2 = (Employee) harry.clone();
      System.out.println(harry==harry2);
      System.out.println(harry);
      System.out.println(harry2);
   }
}
 
/**
   A class whose clone method uses serialization.
*/
class SerialCloneable implements Cloneable, Serializable
{ 
	private static final long serialVersionUID = 1L;
	//深拷貝
   public Object clone()
   {  
      try
      {  
         // save the object to a byte array
    	 //將該物件序列化成流,因為寫在流裡的是物件的一個拷貝,而原物件仍然存在於JVM裡面
         ByteArrayOutputStream bout = new ByteArrayOutputStream();
         ObjectOutputStream out = new ObjectOutputStream(bout);
         out.writeObject(this);
         out.close();
 
         // read a clone of the object from the byte array
         ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
         ObjectInputStream in = new ObjectInputStream(bin);
         Object ret = in.readObject();
         in.close();
 
         return ret;
      }  
      catch (Exception e)
      {  
         return null;
      }
   }
}
 
/**
   The familiar Employee class, redefined to extend the
   SerialCloneable class. 
*/
class Employee extends SerialCloneable
{  
   
	private static final long serialVersionUID = 1L;
    private String name;
    private double salary;
 
   public Employee(String n, double s)
   {  
      name = n;
      salary = s;
     
   }
 
   public String getName()
   {  
      return name;
   }
 
   public double getSalary()
   {  
      return salary;
   }
   public String toString()
   {  
      return getClass().getName()
         + "[name=" + name
         + ",salary=" + salary
         + "]";
   }
}

四、BeanUtils.copyProperties()

三個測試類

public class Person {
    private String name;
    private String sex;
    private int age;
    private Date birthday;

    private Dog dog;

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    private Double high;


    public String getName() {
        return name;
    }

    public Double getHigh() {
        return high;
    }

    public void setHigh(Double high) {
        this.high = high;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                ", dog=" + dog +
                ", high=" + high +
                '}';
    }
}
public class Dog {
    public String dogName;

    public String getDogName() {
        return dogName;
    }

    public void setDogName(String dogName) {
        this.dogName = dogName;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "dogName='" + dogName + '\'' +
                '}';
    }
}
import org.apache.commons.beanutils.BeanUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.Date;

public class BeanUtilTest {
    public static void main(String[] args) {
        Person per = new Person();
        Person per1 = new Person();
        per.setName("zhangsan");
        per.setSex("男");
        per.setAge(20);
        per.setBirthday(new Date());
        Dog dog = new Dog();
        dog.setDogName("1111111111111111");
        per.setDog(dog);
        try {
            BeanUtils.copyProperties(per1, per);
            Dog dog1 = per.getDog();
            dog1.setDogName("2222222222222222");
            per.setName("666666666666");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        System.out.println(per.toString());
        System.out.println(per1.toString());

    }
}

輸出:

Person{name='666666666666', sex='男', age=20, birthday=Wed Jul 25 18:21:29 CST 2018, dog=Dog{dogName='2222222222222222'}, high=null}
Person{name='zhangsan', sex='男', age=20, birthday=Wed Jul 25 18:21:29 CST 2018, dog=Dog{dogName='2222222222222222'}, high=0.0}

總結:

1、針對物件中的一般欄位可以實現複製物件和源物件各自修改互不影響(如person的name屬性)

2、針對裡面的引用物件,沒有實現巢狀的拷貝(如Dog物件)

參考:

Java核心技術

相關推薦

Java物件複製方式

我們都是愛情的草,在寒冷中死去,在溫暖中重生,四季輪迴,為了愛情不計仇恨。——《我有一杯酒,可以蔚風塵》 1、概述 在實際程式設計過程中,我們常常要遇到這種情況:有一個物件A,在某一時刻A中已經包含了一些有效值,此時可能 會需要一個和A完全相同新

java】陣列複製方式比較

import java.util.Arrays; /** * System.arraycopy方法的使用。 * 從指定源陣列中複製一個數組,複製從指定的位置開始,到目標陣列的指定位置結束 藉助於一個臨時長度為length的陣列 */ public class Less

java實現同步的方式(總結)

副本 增刪改 否則 都是 fin ret 語義 value art 為何要使用同步? java允許多線程並發控制,當多個線程同時操作一個可共享的資源變量時(如數據的增刪改查), 將會導致數據不準確,相互之間產生沖突,因此加入同步鎖以避免在該線程沒有完成操

設計模式之單例模式【內附物件例項化方式、實現執行緒安全方式

繼續來複習常用的設計模式-單例模式,順便回憶一下執行緒安全的幾種實現方式。 一、什麼是單例模式 單例模式,簡單常用的一種設計模式,也很好的體現了程式碼控制物件在記憶體數量的一種方式,主要分2種實現方式: ①餓漢式,執行緒安全 ②懶漢式,執行緒不安全(新增鎖機制,可以實現執行緒安全)

java開發webservice的方式(轉)

java開發webservice的幾種方式(轉) webservice的應用已經越來越廣泛了,下面介紹幾種在Java體系中開發webservice的方式,相當於做個記錄。 1.Axis2 Axis是apache下一個開源的webservice開發元件,出現的算是比較早了,也

java 字串擷取的方式

java 字串擷取的幾種方式 1.split()+正則表示式來進行擷取。  將正則傳入split()。返回的是一個字串陣列型別。不過通過這種方式擷取會有很大的效能損耗,因為分析正則非常耗時。 String str = "abc,12,3yy98,0"; String[] strs

java字串拼接的方式

1. plus方式 當左右兩個量其中有一個為String型別時,用plus方式可將兩個量轉成字串並拼接。 String a="";int b=0xb;String c=a+b;2. concat方式 當兩個量都為String型別且值不為null時,可以用concat方式。 String a="a";S

JS物件宣告的方式

-- 新手向知識,就不用ES6寫法了。 一、字面量宣告 var obj = { 屬性名1 : 屬性值, 屬性名2 : 屬性值, 屬性名3 : 屬性值, 方法名1 : function() {

java檔案下載的方式

 轉載地址 1.通過流下載 public void download(String id, HttpServletResponse response) { response.setHeader("Access-Control-Allow-Origin",

Java建立陣列的方式

借鑑http://blog.csdn.net/u014199097/article/details/50551731 1、一維陣列的宣告 T[] arrayName; 或 T arrayName[];  附:推薦使用第一種格式,因為第一種格式具有更好的可讀性,表示T[]是一

Java下載檔案的方式

1.以流的方式下載 public HttpServletResponse download(String path, HttpServletResponse response) { try { // path是指欲下載的檔案的路徑。

關於JAVA呼叫C++的方式和一些問題 UnsatisfiedLinkError

關於JAVA呼叫C++的幾種方式和一些問題 java呼叫c++有幾種方式,1.JNA方式,2,JNative 方式,3.JNI 方式。: 1.JNA方式 public interface MyCLibrary extends Library {

Java中定義常量方式

在開發中定義常量是很常見的事,但常量定義有哪幾種方式可選?各種定義方式有什麼優缺點?咱們就用這篇小文來梳理下^_^ 1.通過介面Interface來定義(不推薦) 定義方式如下: 我們可以這樣使用它: 這種定義方式的優點: 適合懶人使用,為什麼呢?

java整合groovy的方式對比

   Groovy的幾種整合方式:groovyshell、GroovyClassLoader、GroovyScriptEngine,其中groovyshell的方式不支援指令碼快取,會導致垃圾回收頻繁

java 字串擷取的方式(轉)

眾所周知,java提供了很多字串擷取的方式。下面就來看看大致有幾種。 1.split()+正則表示式來進行擷取。 將正則傳入split()。返回的是一個字串陣列型別。不過通過這種方式擷取會有很大的效能損耗,因為分析正則非常耗時。 String str = "abc,12,3yy98

Java 切割字串的方式

//以data 為案例引數。 String data = "2019-01-08 21:55 136 \n2019-01-08 22:00 86 \n2019-01-08 22:04 136 \n2019-01-08 22:09 86 \n2019-01-08 22:

OpenCv學習筆記(五)--建立Mat矩陣物件常用的方式

/********************************************************************************************* 程式功能: 建立矩陣的幾種方法 編寫環境: Open

Java資料庫連線池方式及其特點

主流的資料庫連線池  在目前技術前沿比較流行的資料庫連線池有:DBCP、Tomcat Jdbc Pool、BoneCP、Druid、C3P0等 DBCP:由Apache開發的一個Java資料庫連線池專案, Jakarta commons-pool物件池機制,Tomcat使

Java傳送郵件的方式

最近的一個專案中用到了郵件傳送,所以研究了一下。將其總結下來。 要傳送郵件就要用到java中的JavaMail,關於JavaMailAPI的詳解呢在 (http://blog.csdn.net/imain/article/details/1453677“)中