最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

探討java深拷貝

 更新時間:2016年02月14日 14:19:53   作者:楚巖  
這篇文章主要針對java深拷貝的相關(guān)內(nèi)容進(jìn)行解析,幫助大家學(xué)習(xí)理解java深拷貝,感興趣的小伙伴們可以參考一下

本文將討論以下4個問題

    1. java Cloneable接口實現(xiàn)深拷貝
    2. java 序列化實現(xiàn)深拷貝
    3. 號稱最快的深拷貝二方庫cloning源碼分析
    4. 幾種拷貝方式速度的比較

深拷貝的概念本文就不說了。在C++中實現(xiàn)深拷貝一般情況下重載賦值操作符 “=” 來實現(xiàn)同一個類的對象間的深拷貝,所以很自然的在java中我們也同樣可以定義一個copy函數(shù),在函數(shù)內(nèi)部為對象的每一個屬性作賦值操作。這種方式簡單自然,但存在一個致命性的問題:如果有一天在類中新增加了一個需要深拷貝的屬性,那么相應(yīng)的copy函數(shù)也得進(jìn)行修改,這種方法給類的可擴(kuò)展性帶來了極大的不方便。怎么解決這種問題,且看接下來的1、2、3章節(jié)的實現(xiàn)方式和4節(jié)的速度測試。
1. java Cloneable接口實現(xiàn)深拷貝
這種方式,需要類實現(xiàn)Colneable接口 clone 函數(shù),在clone函數(shù)中調(diào)用super.clone。這種方式的深拷貝同樣會帶來另一個問題,如果類中有其他類的對象作為屬性,則其他的類也需要重載并實現(xiàn)Cloneable接口。來一個例子,在下例中ComplexDO中包含了SimpleDO對象,要實現(xiàn)ComplexDO深拷貝,則需要先實現(xiàn)SimpleDO的clone接口:

public class SimpleDO implements Cloneable, Serializable {
    private int x = 1;
    private String s = "simpleDO";

    @Override
    protected Object clone() throws CloneNotSupportedException {
      SimpleDO newClass = (SimpleDO)super.clone();
      return newClass;
    }
  }

  public class ComplexDO implements Cloneable, Serializable {
    private int x = 1;
    private String s = "complex";
    private Integer a = 123;
    private Integer b = 1234;
    private Integer c = 1334455;
    private String s2 = "hehehe";
    private String s3 = "hahahaha";
    private Long id = 1233245L;
    private ArrayList<SimpleDO> l = new ArrayList<SimpleDO>();

    @Override
    public Object clone() throws CloneNotSupportedException {
      ComplexDO newClass = (ComplexDO) super.clone();
      newClass.l = new ArrayList<SimpleDO>();
      for (SimpleDO simple : this.l) {
        newClass.l.add((SimpleDO) simple.clone());
      }
      return newClass;
    }
  }

需要注意的是很多文章說String類型的對象賦值操作符是深拷貝,但是其實在java中使用賦值操作符的都屬于淺拷貝,但為什么這么明顯的錯誤這么多的文章會非要說這個是深拷貝呢?我的理解是String、類型的屬性都是基本類型,而且提供的方法只要是設(shè)計到內(nèi)部數(shù)據(jù)的變動都會new一個新的對象出來。所以一個String的操作不會影響到其原先指向的內(nèi)存。所以一般說String等基礎(chǔ)類的賦值操作為深拷貝。
由于這個原因,在使用String字符串拼接的時候,需要開辟新的內(nèi)存,所以很多人建議用StringBuilder來代替String來做拼接,因為StringBuilder只有在內(nèi)置的char數(shù)組范圍不夠的時候才重新申請更大的內(nèi)存(對于現(xiàn)代JVM,會對代碼調(diào)優(yōu),String+String會被優(yōu)化成StringBuilder.append的相類似的指令)。與拼接相對的裁剪,在String有個subString函數(shù),當(dāng)使用subString函數(shù)時,新String的內(nèi)部char數(shù)組和原String是否相同?這個比較有意思,感興趣的可以對比看看JDK1.6和JKD1.7的實現(xiàn)。
2. java 序列化實現(xiàn)深拷貝
這種方式的原理是利用java序列化,將一個對象序列化成二進(jìn)制字節(jié)流,然后對該字節(jié)流反序列化賦值給一個對象。代碼示例:

  public Object seirCopy(Object src) {
    try {
      ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
      ObjectOutputStream out = new ObjectOutputStream(byteOut);
      out.writeObject(src);

      ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
      ObjectInputStream in = new ObjectInputStream(byteIn);
      Object dest = in.readObject();
      return dest;
    } catch (Exception e) {
      //do some error handler
      return null;
    }
 }

當(dāng)然,也可以選用json等序列化的庫來完成序列化,這種方式有效的規(guī)避了Cloneabel接口的可擴(kuò)展缺點,一個函數(shù)就可以基本上適用于所有的類.缺點是相對內(nèi)存拷貝,序列化需要先將對象轉(zhuǎn)換成二進(jìn)制字節(jié)流,然后反序列化將該二進(jìn)制字節(jié)流重新拷貝到一塊對象內(nèi)存,相對慢點。
3. 號稱最快的深拷貝二方庫cloning源碼分析
在源碼中,核心的處理邏輯在Cloner類中,
分兩條遞歸鏈路:

  • (1)deepClone->cloneInternal->fastClone->cloneInternal
  • (2)deepClone->cloneInternal->cloneObject->cloneInternal

在(1)中fastClone完成的是繼承自IfastCloner接口類的對象,即都是些集合操作的拷貝;
在(2)中cloneObject完成的是通過反射機(jī)制拿到普通對象的每一個屬性,然后對使用Objenesis新生成對象的屬性賦值。
這種方式可擴(kuò)展性強(qiáng),不僅可以依靠其現(xiàn)有的代碼完成深拷貝,還可以自己定義一些克隆的方式和不需要克隆的類型,靈活性強(qiáng)。
4. 幾種拷貝方式速度的比較
上述3中模式都可以完成深拷貝,那種拷貝的方式速度最快是我們所關(guān)心的。
先上測試代碼:
 

  public void testCloneComplex() throws CloneNotSupportedException {
    final int copyCount = 1;
    List<ComplexDO> complexDOList = new ArrayList<ComplexDO>(copyCount * 3);
    final ComplexDO complex = new ComplexDO();

    //調(diào)用二方庫
    long start = System.currentTimeMillis();
    for(int i = 0; i < copyCount; ++i) {
      final ComplexDO deepClone = cloner.deepClone(complex);
      complexDOList.add(deepClone);
    }
    long end = System.currentTimeMillis();
    System.out.println("deepClone cost time=" + (end-start));

    //調(diào)用Cloneable接口實現(xiàn)的clone函數(shù)
    start = System.currentTimeMillis();
    for(int i = 0; i < copyCount; ++i) {
      final ComplexDO interfaceClone = (ComplexDO) complex.clone();
      complexDOList.add(interfaceClone);
    }
    end = System.currentTimeMillis();
    System.out.println("interfaceClone cost time=" + (end-start));

    //序列化與反序列化生成新對象
    start = System.currentTimeMillis();
    for(int i = 0; i < copyCount; ++i) {
      final ComplexDO seirClone = seirCopy(complex);
      complexDOList.add(seirClone);
    }
    end = System.currentTimeMillis();
    System.out.println("seirClone cost time=" + (end-start));
  }


運(yùn)行結(jié)果的單位為毫秒(此數(shù)據(jù)忽略不計算java熱點和可能的gc)。

從這個表可以得出結(jié)論:

1、實現(xiàn)Cloneable接口的拷貝是最快的,因為他只涉及到了內(nèi)存拷貝,但是如果涉及的屬性為普通對象比較多的時候?qū)懫饋砺闊c
2、序列化/反序列化拷貝最慢
3、使用cloning庫,由于使用了遞歸和反射機(jī)制相對Cloneable接口實現(xiàn)的拷貝要慢,但比序列化方式要快。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。

相關(guān)文章

  • Spring?BeanFactory容器的構(gòu)建和使用示例詳解

    Spring?BeanFactory容器的構(gòu)建和使用示例詳解

    BeanFactory是Spring框架中的一部分,它提供了IoC(控制反轉(zhuǎn))的實現(xiàn)機(jī)制,下面小編就來和大家簡單聊聊BeanFactory容器的構(gòu)建和使用示例吧
    2023-07-07
  • java計算兩個日期中間的時間

    java計算兩個日期中間的時間

    這篇文章主要介紹了java計算兩個日期中間的時間的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • SpringBoot實現(xiàn)登錄攔截的示例代碼

    SpringBoot實現(xiàn)登錄攔截的示例代碼

    如果我們不進(jìn)行登錄攔截的話,即使我們跳過登錄頁面直接去訪問任意一個頁面也能訪問成功,那么登錄功能就沒有意義,同時也會存在安全問題,本文就來介紹一下SpringBoot登錄攔截,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • springboot注解及GET、POST接口寫法

    springboot注解及GET、POST接口寫法

    springboot提供了@Contrller和@RestController注解,@Controller返回頁面和數(shù)據(jù)而@RestController返回數(shù)據(jù),本文重點介紹springboot注解及GET、POST接口寫法,感興趣的朋友一起看看吧
    2024-04-04
  • 詳解SpringMVC的攔截器參數(shù)及攔截器鏈配置

    詳解SpringMVC的攔截器參數(shù)及攔截器鏈配置

    攔截器(Interceptor)是一種動態(tài)攔截方法調(diào)用的機(jī)制,在SpringMVC中動態(tài)攔截控制器方法的執(zhí)行。本文將詳細(xì)講講SpringMVC中攔截器參數(shù)及攔截器鏈配置,感興趣的可以嘗試一下
    2022-07-07
  • Spring定時服務(wù)QuartZ原理及代碼案例

    Spring定時服務(wù)QuartZ原理及代碼案例

    這篇文章主要介紹了Spring定時服務(wù)QuartZ原理及代碼案例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-11-11
  • Java 基于Spire.Cloud.SDK for Java在PDF中繪制形狀

    Java 基于Spire.Cloud.SDK for Java在PDF中繪制形狀

    這篇文章主要介紹了Java 基于Spire.Cloud.SDK for Java在PDF中繪制形狀,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Java中Date、LocalDate、LocalDateTime、LocalTime、時間戳之間的相互轉(zhuǎn)換代碼

    Java中Date、LocalDate、LocalDateTime、LocalTime、時間戳之間的相互轉(zhuǎn)換代碼

    這篇文章主要介紹了Java中日期時間轉(zhuǎn)換的多種方法,包括將Date轉(zhuǎn)換為LocalDateTime、LocalDate等,以及將時間戳轉(zhuǎn)換為LocalDateTime,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-04-04
  • Java Springboot 重要知識點整理匯總

    Java Springboot 重要知識點整理匯總

    Spring Boot作為微服務(wù)中最好的Java框架,本文主要為大家整理匯總了七個Spring Boot的重要知識點,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2021-11-11
  • 深入解析Java的設(shè)計模式編程中建造者模式的運(yùn)用

    深入解析Java的設(shè)計模式編程中建造者模式的運(yùn)用

    這篇文章主要介紹了深入解析Java的設(shè)計模式編程中建造者模式的運(yùn)用,同時文中也介紹了建造者模式與工廠模式的區(qū)別,需要的朋友可以參考下
    2016-02-02

最新評論

板桥市| 甘孜| 思南县| 乐山市| 浪卡子县| 大埔区| 长顺县| 湖北省| 辉南县| 苍溪县| 无棣县| 兰坪| 筠连县| 临猗县| 伊川县| 礼泉县| 通榆县| 宁波市| 田林县| 香格里拉县| 乐安县| 隆安县| 观塘区| 保靖县| 邛崃市| 山阳县| 四平市| 灵山县| 舒兰市| 屯昌县| 宝丰县| 贵南县| 浙江省| 晋州市| 丹寨县| 上杭县| 洮南市| 巴东县| 乌拉特中旗| 安阳市| 长乐市|