日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

深度拷贝 java_Java深度拷贝方式和性能对比

發布時間:2025/3/19 java 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深度拷贝 java_Java深度拷贝方式和性能对比 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

Java的深度拷貝大致分為克隆(實現Java的Clone接口)和序列化(實現Java的Serializable接口)兩種,但是基于不同的序列化方式,有可以延伸出幾種方式。下面分析一下每種的注意事項和性能對比【當前電腦為4核16G,只是當前使用main方法單線程測試】。

一、拷貝和深淺拷貝

可以使用Java native方法提供的Clone方式進行對象的拷貝,其性能是最高的,甚至高過new 關鍵字。使用new關鍵字創建對象,如果是第一次創建則會經歷類加載機制的雙親委派(加載、驗證、準備、解析、初始化)。即使非第一次創建也會經歷(常量池判斷,內存分配,值初始化,init方法調用,棧中對象的引用等)等過程。

我們需要繼承自Clone接口,重寫Object的clone方法。如下:

public class DeepCopyEntity implements Cloneable {

@Override

protected DeepCopyEntity clone() {

try {

return (DeepCopyEntity)super.clone();

} catch (CloneNotSupportedException e) {

log.info("沒有實現克隆接口");

return null;

}

}

}

但是我們在使用的時候,需要每個對象都編寫這樣的代碼。可以優化為繼承自類似下面的 CloneSupport 類(前體是沒有繼承其他的類):

public class CloneSupport implements Cloneable {

@SuppressWarnings("unchecked")

@Override

public T clone() {

try {

return (T) super.clone();

} catch (CloneNotSupportedException e) {

throw new CloneRuntimeException(e);

}

}

}

但是即使是克隆之后的對象也是淺拷貝。即對象的屬性如果是非基本數據類型和String的情況下,新老對象的對象屬性的內存地址任然相同,則任何一個對象改變其值之后,另一個對象的值也就是改變了,這很多時候可能是我們不想要的。那么需要進行深度的拷貝。則需要其屬性對象的類也繼承自Clone接口,并且重新clone方法。如下(是我項目中使用的):

public class PurOrderSkuBO implements Serializable, Cloneable {

@Override

public PurOrderSkuBO clone() {

try {

final PurOrderSkuBO clone = (PurOrderSkuBO) super.clone();

clone.purOrderSkuDTO = purOrderSkuDTO.clone();

clone.productList = productList.stream().map(PurOrderItemBO::clone).collect(Collectors.toList());

return clone;

} catch (CloneNotSupportedException e) {

return new PurOrderSkuBO();

}

}

private PurOrderSkuDTO purOrderSkuDTO;

private List productList;

}

public class PurOrderSkuDTO extends CloneSupport {

}

二、序列化

另一種實現深度拷貝的方式就是序列化,無論是Jdk的序列化還是其他方式的序列化都需要實現自 java.io.Serializable接口,并且設置自己的serialVersionUID,并且保證項目中不能有相同的值(很多開發的時候,基于原來的類copy過來后需要進行修改),如下:

public class DeepCopyEntity implements Cloneable, Serializable {

private static final long serialVersionUID = 6172279441386879379L;

}

三、深度拷貝的方式

1、new關鍵字

實現對象的深度拷貝,就是對象的每一層屬性的內存地址都不相同,那么基于new 對象,再每一層設置new的屬性對象。也是可以實現的,或者基于反射的方式,并且性能也是比較高的。需要注意jdk 6及之前的反射性能比較差。

優點:性能高,缺點:就是每個對象都需要new,并且每一層都需要用setter等進行賦值【硬編碼】。

2、Clone

優點:性能高,缺點:所有層級只要有屬性對象就需要實現Clone,并且重寫clone方法。如果對象有七八層,其中每一層的每一個地方沒有注意到就可能非深拷貝。

3、jdk序列化

jdk序列化只需要基于ObjectOutputStream將原對象流寫出去(寫入本地磁盤),再基于ObjectInputStream將對象流讀回來即可。如下:

/**

* 深層拷貝 - 需要類繼承序列化接口

* @param 對象類型

* @param obj 原對象

* @return 深度拷貝的對象

* @throws Exception

* @see java.io.Closeable

* @see AutoCloseable 不用進行關閉

*/

@SuppressWarnings("unchecked")

public static T copyImplSerializable(T obj) throws Exception {

ByteArrayOutputStream baos = null;

ObjectOutputStream oos = null;

ByteArrayInputStream bais = null;

ObjectInputStream ois = null;

Object o = null;

//如果子類沒有繼承該接口,這一步會報錯

try {

baos = new ByteArrayOutputStream();

oos = new ObjectOutputStream(baos);

oos.writeObject(obj);

bais = new ByteArrayInputStream(baos.toByteArray());

ois = new ObjectInputStream(bais);

o = ois.readObject();

return (T) o;

} catch (Exception e) {

throw new Exception("對象中包含沒有繼承序列化的對象");

}

}

優點:不需要像克隆和new一樣單獨開發,缺點:性能比較差

4、kyro序列化

kyro需要單獨引入maven依賴,如:

com.esotericsoftware

kryo

5.0.0-RC9

使用時需要創建 Kryo對象【 Kryo kryo = new Kryo(); 】,只是該對象是非線程安全的,所有如果在項目中使用時,最好放到ThreadLocal中進行創建。使用就比較簡單了:

public static T copyByKryo(T source){

return kryo.copy(source);

}

優點:性能較高, 缺點:需要單獨引入maven,性能比new 和clone的低一點

5、Json序列化

項目上使用Json 進行 redis、rpc調用(如 Spring Cloud Feign) 進行序列化和反序列化是比較常用的,但是如果僅僅是本地深度拷貝,則使用該方式性能是最差的。可以在下面進行比較,各種json框架的序列化方式都差不多。

四、性能對比

創建一個50個字段的對象,并使用不同的深度拷貝方式,創建對象N多遍。

@Data

@NoArgsConstructor

@AllArgsConstructor

public class DeepCopyEntity implements Cloneable, Serializable {

/**

* 序列化標識

*/

private static final long serialVersionUID = 6172279441386879379L;

@Override

protected DeepCopyEntity clone() {

try {

return (DeepCopyEntity)super.clone();

} catch (CloneNotSupportedException e) {

e.printStackTrace();

return null;

}

}

private String id;

private String field1;

private String field2;

private String field3;

private String field4;

private String field5;

private String field6;

private String field7;

private String field8;

private String field9;

private String field10;

private String field11;

private String field12;

private String field13;

private String field14;

private String field15;

private String field16;

private String field17;

private String field18;

private String field19;

private String field20;

private String field21;

private String field22;

private String field23;

private String field24;

private String field25;

private String field26;

private String field27;

private String field28;

private String field29;

private String field30;

private String field31;

private String field32;

private String field33;

private String field34;

private String field35;

private String field36;

private String field37;

private String field38;

private String field39;

private String field40;

private String field41;

private String field42;

private String field43;

private String field44;

private String field45;

private String field46;

private String field47;

private String field48;

private String field49;

private String field50;

}

package com.kevin.deepcopy;

import com.esotericsoftware.kryo.Kryo;

import net.sf.json.JSONObject;

import org.springframework.util.StopWatch;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

/**

* 深度拷貝類型 循環次數[1000] 循環次數[10000] 循環次數[1000000]

* new 5 ms 14 ms 133 ms

*

* Cloneable: < 1 ms 7 ms 88 ms

*

* Jdk序列化: 272 ms 1589 ms 66190 ms

*

* Kryo序列化: 95 ms 123 ms 2438 ms

*

* Json序列化: 1203 ms 3746 ms 163512 ms

*

* 總結: 1)、序列化性能 Clone > new > Kryo序列化 > Jdk序列化 > Json(各種Json類似)序列化

* 2)、Clone深拷貝性能最高,但是如果屬性中有特定的對象字段,則需要自己編寫代碼

* 3)、new 性能僅次于Clone,因為需要執行Jvm過程(常量池判斷,內存分配,值初始化,init方法調用,棧中對象的引用等),并且主要是每個對象需要單獨編寫代碼,當然也不建議使用反射

* 4)、kryo 性能較高,并且不需要單獨的開發, 若對性能不是特別高,可以考慮使用.(kryo是非線程安全的,項目中使用時可以放入ThreadLocal中)

* 5)、Jdk序列化和Json序列化,性能太低,高性能項目不建議使用

*

* 總結的總結: 如果性能要求特別高(或者對象結構層次不深),可以使用Clone方式;否則可以考慮使用 Kryo序列化和反序列化實現對象深拷貝

*

* @author kevin

* @date 2020/9/27 13:45

* @since 1.0.0

*/

public class DeepCopyTest {

/**

* 循環的次數

*/

private static final int LOOP = 1000;

private static Kryo kryo = new Kryo();

public static void main(String[] args) throws Exception {

DeepCopyEntity demo = getInit();

StopWatch stopWatch = new StopWatch("測試深拷貝");

stopWatch.start();

for (int i = 0; i < LOOP; i++) {

// DeepCopyEntity deep = newObject(demo);

final DeepCopyEntity deep = demo.clone();

// final DeepCopyEntity deepCopyEntity = copyImplSerializable(demo);

// final DeepCopyEntity deepCopyEntity = copyByKryo(demo);

// final DeepCopyEntity deepCopyEntity1 = copyByJson(demo);

}

stopWatch.stop();

System.out.println(stopWatch.prettyPrint());

}

/**

* 深層拷貝 - 需要net.sf.json.JSONObject

* @param

* @param obj

* @return

* @throws Exception

*/

@SuppressWarnings("unchecked")

public static T copyByJson(T obj) throws Exception {

return (T) JSONObject.toBean(JSONObject.fromObject(obj),obj.getClass());

}

/**

*

* @param source

* @return

*/

public static DeepCopyEntity copyByKryo(DeepCopyEntity source){

return kryo.copy(source);

}

/**

* 深層拷貝 - 需要類繼承序列化接口

* @param

* @param obj

* @return

* @throws Exception

* @see java.io.Closeable

* @see AutoCloseable 不用進行關閉

*/

@SuppressWarnings("unchecked")

public static T copyImplSerializable(T obj) throws Exception {

ByteArrayOutputStream baos = null;

ObjectOutputStream oos = null;

ByteArrayInputStream bais = null;

ObjectInputStream ois = null;

Object o = null;

//如果子類沒有繼承該接口,這一步會報錯

try {

baos = new ByteArrayOutputStream();

oos = new ObjectOutputStream(baos);

oos.writeObject(obj);

bais = new ByteArrayInputStream(baos.toByteArray());

ois = new ObjectInputStream(bais);

o = ois.readObject();

return (T) o;

} catch (Exception e) {

throw new Exception("對象中包含沒有繼承序列化的對象");

}

}

private static DeepCopyEntity newObject(DeepCopyEntity demo) {

final DeepCopyEntity deepCopyEntity = new DeepCopyEntity();

deepCopyEntity.setId(demo.getId());

deepCopyEntity.setField1(demo.getField1());

deepCopyEntity.setField2(demo.getField2());

deepCopyEntity.setField3(demo.getField1());

deepCopyEntity.setField4(demo.getField1());

deepCopyEntity.setField5(demo.getField1());

deepCopyEntity.setField6(demo.getField1());

deepCopyEntity.setField7(demo.getField1());

deepCopyEntity.setField8(demo.getField1());

deepCopyEntity.setField9(demo.getField1());

deepCopyEntity.setField10(demo.getField1());

deepCopyEntity.setField11(demo.getField1());

deepCopyEntity.setField12(demo.getField1());

deepCopyEntity.setField13(demo.getField1());

deepCopyEntity.setField14(demo.getField1());

deepCopyEntity.setField15(demo.getField1());

deepCopyEntity.setField16(demo.getField1());

deepCopyEntity.setField17(demo.getField1());

deepCopyEntity.setField18(demo.getField1());

deepCopyEntity.setField19(demo.getField1());

deepCopyEntity.setField20(demo.getField1());

deepCopyEntity.setField21(demo.getField1());

deepCopyEntity.setField22(demo.getField1());

deepCopyEntity.setField23(demo.getField1());

deepCopyEntity.setField24(demo.getField1());

deepCopyEntity.setField25(demo.getField1());

deepCopyEntity.setField26(demo.getField1());

deepCopyEntity.setField27(demo.getField1());

deepCopyEntity.setField28(demo.getField1());

deepCopyEntity.setField29(demo.getField1());

deepCopyEntity.setField30(demo.getField1());

deepCopyEntity.setField31(demo.getField1());

deepCopyEntity.setField32(demo.getField1());

deepCopyEntity.setField33(demo.getField1());

deepCopyEntity.setField34(demo.getField1());

deepCopyEntity.setField35(demo.getField1());

deepCopyEntity.setField36(demo.getField1());

deepCopyEntity.setField37(demo.getField1());

deepCopyEntity.setField38(demo.getField1());

deepCopyEntity.setField39(demo.getField1());

deepCopyEntity.setField40(demo.getField1());

deepCopyEntity.setField41(demo.getField1());

deepCopyEntity.setField42(demo.getField1());

deepCopyEntity.setField43(demo.getField1());

deepCopyEntity.setField44(demo.getField1());

deepCopyEntity.setField45(demo.getField1());

deepCopyEntity.setField46(demo.getField1());

deepCopyEntity.setField47(demo.getField1());

deepCopyEntity.setField48(demo.getField1());

deepCopyEntity.setField49(demo.getField1());

deepCopyEntity.setField50(demo.getField1());

return deepCopyEntity;

}

/**

* 獲取初始化值

* @return demo對象

*/

private static DeepCopyEntity getInit() {

final DeepCopyEntity deepCopyEntity = new DeepCopyEntity();

deepCopyEntity.setId("測試字段進來撒個是個是個復活節快樂時刻六公里按時交付格拉斯可根據ask了接受了嘎嘎健康金克拉是個零售價格克拉斯關鍵時刻兩個jklsghbld時間噶設立國家級法國設計規劃拉薩盡快趕回監考老師的風格就是看來撒骨灰兩個據類");

// 省略后面所有字段的設置,都設置一樣的字段 ......

return deepCopyEntity;

}

}

總結:

1)、序列化性能 Clone > new > Kryo序列化 > Jdk序列化 > Json(各種Json類似)序列化

2)、Clone深拷貝性能最高,但是如果屬性中有特定的對象字段,則需要自己編寫代碼

3)、new 性能僅次于Clone,因為需要執行Jvm過程(常量池判斷,內存分配,值初始化,init方法調用,棧中對象的引用等),

并且主要是每個對象需要單獨編寫代碼,當然也不建議使用反射

4)、kryo 性能較高,并且不需要單獨的開發, 若對性能不是特別高,可以考慮使用.

kryo是非線程安全的,項目中使用時可以放入ThreadLocal中

5)、Jdk序列化和Json序列化,性能太低,高性能項目不建議使用

如果性能要求特別高(或者對象結構層次不深),可以使用Clone方式;

否則可以考慮使用 Kryo序列化和反序列化實現對象深拷貝

結尾

本文到這里就結束了,感謝看到最后的朋友,都看到最后了,點個贊再走啊,如有不對之處還請多多指正。

總結

以上是生活随笔為你收集整理的深度拷贝 java_Java深度拷贝方式和性能对比的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。