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

Java對象的復制三種方式(小結(jié))

 更新時間:2019年08月27日 10:22:39   作者:chun_soft  
這篇文章主要介紹了Java對象的復制三種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

1、概述

在實際編程過程中,我們常常要遇到這種情況:有一個對象A,在某一時刻A中已經(jīng)包含了一些有效值,此時可能 會需要一個和A完全相同新對象B,并且此后對B任何改動都不會影響到A中的值,也就是說,A與B是兩個獨立的對象,但B的初始值是由A對象確定的。例如下面程序展示的情況:

class Student { 
  private int number; 
 
  public int getNumber() { 
    return number; 
  } 
 
  public void setNumber(int number) { 
    this.number = number; 
  } 
   
} 
public class Test {  
  public static void main(String args[]) { 
    Student stu1 = new Student(); 
    stu1.setNumber(12345); 
    Student stu2 = stu1; 
    stu1.setNumber(54321); 
    System.out.println("學生1:" + stu1.getNumber()); 
    System.out.println("學生2:" + stu2.getNumber()); 
  } 
}

結(jié)果:

學生1:54321
學生2:54321

為什么改變學生2的學號,學生1的學號也發(fā)生了變化呢?

原因出在(stu2 = stu1) 這一句。該語句的作用是將stu1的引用賦值給stu2,

這樣,stu1和stu2指向內(nèi)存堆中同一個對象。如圖:

那么,怎么能干干凈凈清清楚楚地復制一個對象呢。在 Java語言中,用簡單的賦值語句是不能滿足這種需求的。要滿足這種需求有很多途徑,

(1)將A對象的值分別通過set方法加入B對象中;
(2)通過重寫java.lang.Object類中的方法clone();
(3)通過org.apache.commons中的工具類BeanUtils和PropertyUtils進行對象復制;
(4)通過序列化實現(xiàn)對象的復制。

2、將A對象的值分別通過set方法加入B對象中

對屬性逐個賦值,本實例為了演示簡單就設置了一個屬性:

Student stu1 = new Student(); 
stu1.setNumber(12345); 
Student stu2 = new Student(); 
stu2.setNumber(stu1.getNumber());

我們發(fā)現(xiàn),屬性少對屬性逐個賦值還挺方便,但是屬性多時,就需要一直get、set了,非常麻煩。

3、重寫java.lang.Object類中的方法clone()

先介紹一下兩種不同的克隆方法,淺克隆(ShallowClone)和深克隆(DeepClone)。

在Java語言中,數(shù)據(jù)類型分為值類型(基本數(shù)據(jù)類型)和引用類型,值類型包括int、double、byte、boolean、char等簡單數(shù)據(jù)類型,引用類型包括類、接口、數(shù)組等復雜類型。淺克隆和深克隆的主要區(qū)別在于是否支持引用類型的成員變量的復制,下面將對兩者進行詳細介紹。

3.1 淺克隆

一般步驟:

被復制的類需要實現(xiàn)Clonenable接口(不實現(xiàn)的話在調(diào)用clone方法會拋出CloneNotSupportedException異常), 該接口為標記接口(不含任何方法)

覆蓋clone()方法,訪問修飾符設為public。方法中調(diào)用super.clone()方法得到需要的復制對象。(native為本地方法)

class Student implements Cloneable{ 
  private int number; 
 
  public int getNumber() { 
    return number; 
  } 
 
  public void setNumber(int number) { 
    this.number = number; 
  } 
   
  @Override 
  public Object clone() { 
    Student stu = null; 
    try{ 
      stu = (Student)super.clone(); 
    }catch(CloneNotSupportedException e) { 
      e.printStackTrace(); 
    } 
    return stu; 
  } 
} 
public class Test { 
  public static void main(String args[]) { 
    Student stu1 = new Student(); 
    stu1.setNumber(12345); 
    Student stu2 = (Student)stu1.clone(); 
     
    System.out.println("學生1:" + stu1.getNumber()); 
    System.out.println("學生2:" + stu2.getNumber()); 
     
    stu2.setNumber(54321); 
   
    System.out.println("學生1:" + stu1.getNumber()); 
    System.out.println("學生2:" + stu2.getNumber()); 
  } 
} 

結(jié)果:
學生1:12345
學生2:12345
學生1:12345
學生2:54321

在淺克隆中,如果原型對象的成員變量是值類型,將復制一份給克隆對象;如果原型對象的成員變量是引用類型,則將引用對象的地址復制一份給克隆對象,也就是說原型對象和克隆對象的成員變量指向相同的內(nèi)存地址。

簡單來說,在淺克隆中,當對象被復制時只復制它本身和其中包含的值類型的成員變量,而引用類型的成員對象并沒有復制。


在Java語言中,通過覆蓋Object類的clone()方法可以實現(xiàn)淺克隆。

3.2 深克隆

package abc; 
 
class Address { 
  private String add; 
 
  public String getAdd() { 
    return add; 
  } 
 
  public void setAdd(String add) { 
    this.add = add; 
  }  
} 
 
class Student implements Cloneable{ 
  private int number; 
 
  private Address addr; 
   
  public Address getAddr() { 
    return addr; 
  } 
 
  public void setAddr(Address addr) { 
    this.addr = addr; 
  } 
 
  public int getNumber() { 
    return number; 
  } 
 
  public void setNumber(int number) { 
    this.number = number; 
  } 
   
  @Override 
  public Object clone() { 
    Student stu = null; 
    try{ 
      stu = (Student)super.clone();  //淺復制 
    }catch(CloneNotSupportedException e) { 
      e.printStackTrace(); 
    }  
    return stu; 
  } 
} 
public class Test { 
   
  public static void main(String args[]) { 
     
    Address addr = new Address(); 
    addr.setAdd("杭州市"); 
    Student stu1 = new Student(); 
    stu1.setNumber(123); 
    stu1.setAddr(addr); 
     
    Student stu2 = (Student)stu1.clone(); 
     
    System.out.println("學生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd()); 
    System.out.println("學生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd()); 
     
    addr.setAdd("西湖區(qū)"); 
     
    System.out.println("學生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd()); 
    System.out.println("學生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd()); 
  } 
}

結(jié)果:
學生1:123,地址:杭州市
學生2:123,地址:杭州市
學生1:123,地址:西湖區(qū)
學生2:123,地址:西湖區(qū)

怎么兩個學生的地址都改變了?

原因是淺復制只是復制了addr變量的引用,并沒有真正的開辟另一塊空間,將值復制后再將引用返回給新對象。

為了達到真正的復制對象,而不是純粹引用復制。我們需要將Address類可復制化,并且修改clone方法,完整代碼如下:

package abc; 
 
class Address implements Cloneable { 
  private String add; 
 
  public String getAdd() { 
    return add; 
  } 
 
  public void setAdd(String add) { 
    this.add = add; 
  } 
   
  @Override 
  public Object clone() { 
    Address addr = null; 
    try{ 
      addr = (Address)super.clone(); 
    }catch(CloneNotSupportedException e) { 
      e.printStackTrace(); 
    } 
    return addr; 
  } 
} 
 
class Student implements Cloneable{ 
  private int number; 
 
  private Address addr; 
   
  public Address getAddr() { 
    return addr; 
  } 
 
  public void setAddr(Address addr) { 
    this.addr = addr; 
  } 
 
  public int getNumber() { 
    return number; 
  } 
 
  public void setNumber(int number) { 
    this.number = number; 
  } 
   
  @Override 
  public Object clone() { 
    Student stu = null; 
    try{ 
      stu = (Student)super.clone();  //淺復制 
    }catch(CloneNotSupportedException e) { 
      e.printStackTrace(); 
    } 
    stu.addr = (Address)addr.clone();  //深度復制 
    return stu; 
  } 
} 
public class Test { 
   
  public static void main(String args[]) { 
     
    Address addr = new Address(); 
    addr.setAdd("杭州市"); 
    Student stu1 = new Student(); 
    stu1.setNumber(123); 
    stu1.setAddr(addr); 
     
    Student stu2 = (Student)stu1.clone(); 
     
    System.out.println("學生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd()); 
    System.out.println("學生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd()); 
     
    addr.setAdd("西湖區(qū)"); 
     
    System.out.println("學生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd()); 
    System.out.println("學生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd()); 
  } 
}

結(jié)果:
學生1:123,地址:杭州市
學生2:123,地址:杭州市
學生1:123,地址:西湖區(qū)
學生2:123,地址:杭州市

在深克隆中,無論原型對象的成員變量是值類型還是引用類型,都將復制一份給克隆對象,深克隆將原型對象的所有引用對象也復制一份給克隆對象。

簡單來說,在深克隆中,除了對象本身被復制外,對象所包含的所有成員變量也將復制。


在Java語言中,如果需要實現(xiàn)深克隆,可以通過覆蓋Object類的clone()方法實現(xiàn),也可以通過序列化(Serialization)等方式來實現(xiàn)。

(如果引用類型里面還包含很多引用類型,或者內(nèi)層引用類型的類里面又包含引用類型,使用clone方法就會很麻煩。這時我們可以用序列化的方式來實現(xiàn)對象的深克隆。)

4、工具類BeanUtils和PropertyUtils進行對象復制

Student stu1 = new Student(); 
stu1.setNumber(12345); 
Student stu2 = new Student(); 
BeanUtils.copyProperties(stu2,stu1);

這種寫法無論多少種屬性都只需要一行代碼搞定,很方便吧!除BeanUtils外還有一個名為PropertyUtils的工具類,它也提供copyProperties()方法,作用與BeanUtils的同名方法十分相似,主要的區(qū)別在于BeanUtils提供類型轉(zhuǎn)換功能,即發(fā)現(xiàn)兩個JavaBean的同名屬性為不同類型時,在支持的數(shù)據(jù)類型范圍內(nèi)進行轉(zhuǎn)換,而PropertyUtils不支持這個功能,但是速度會更快一些。在實際開發(fā)中,BeanUtils使用更普遍一點,犯錯的風險更低一點。

5、通過序列化實現(xiàn)對象的復制

序列化就是將對象寫到流的過程,寫到流中的對象是原有對象的一個拷貝,而原對象仍然存在于內(nèi)存中。通過序列化實現(xiàn)的拷貝不僅可以復制對象本身,而且可以復制其引用的成員對象,因此通過序列化將對象寫到一個流中,再從流里將其讀出來,可

以實現(xiàn)深克隆。需要注意的是能夠?qū)崿F(xiàn)序列化的對象其類必須實現(xiàn)Serializable接口,否則無法實現(xiàn)序列化操作。

相關(guān)文章

  • JavaCV調(diào)用百度AI實現(xiàn)人臉檢測方法詳解

    JavaCV調(diào)用百度AI實現(xiàn)人臉檢測方法詳解

    在檢測人臉數(shù)量、位置、性別、口罩等場景時,可以考慮使用百度開放平臺提供的web接口,一個web請求就能完成檢測得到結(jié)果。本文就為大家介紹JavaCV如何調(diào)用百度AI實現(xiàn)最簡單的人臉檢測,需要的可以參考一下
    2022-01-01
  • Java中BigDecimal類的使用詳解

    Java中BigDecimal類的使用詳解

    這篇文章主要介紹了Java中BigDecimal類的使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • Java常用類之比較器的使用詳解

    Java常用類之比較器的使用詳解

    這篇文章主要為大家詳細介紹了Java中比較器的相關(guān)資料,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2022-11-11
  • Java中Map的entrySet()使用說明

    Java中Map的entrySet()使用說明

    這篇文章主要介紹了Java中Map的entrySet()使用說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • SpringCloud分布式鏈路跟蹤的方法

    SpringCloud分布式鏈路跟蹤的方法

    這篇文章主要介紹了SpringCloud分布式鏈路跟蹤的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-03-03
  • 詳解MyBatis-Puls中saveBatch批量添加慢的問題

    詳解MyBatis-Puls中saveBatch批量添加慢的問題

    本文主要介紹了詳解MyBatis-Puls中saveBatch批量添加慢的問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-01-01
  • 解決idea?中?SpringBoot?點擊運行沒反應按鈕成灰色的問題

    解決idea?中?SpringBoot?點擊運行沒反應按鈕成灰色的問題

    在使用 Spring Boot 開發(fā)項目時,可能會遇到一個問題:點擊運行按鈕后,控制臺沒有任何輸出,項目界面也沒有顯示,這種情況可能是由多種原因?qū)е碌模疚膶⒔榻B一些常見的解決方法,需要的朋友可以參考下
    2023-08-08
  • Java?List集合取交集的五種常見方式總結(jié)

    Java?List集合取交集的五種常見方式總結(jié)

    在Java中取兩個List集合的交集可以通過多種方式實現(xiàn),下面這篇文章主要給大家介紹了關(guān)于Java?List集合取交集的五種常見方式,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-07-07
  • 關(guān)于Java的對象序列化流和反序列化流詳細解讀

    關(guān)于Java的對象序列化流和反序列化流詳細解讀

    這篇文章主要介紹了關(guān)于Java的對象序列化流和反序列化流,對象序列化:就是將對象保存到磁盤中,或者在網(wǎng)絡中傳輸對象,反之,自己序列還可以從文件中讀取回來,重構(gòu)對象,對它進行反序列化,需要的朋友可以參考下
    2023-05-05
  • mybatis?mapper.xml中如何根據(jù)數(shù)據(jù)庫類型選擇對應SQL語句

    mybatis?mapper.xml中如何根據(jù)數(shù)據(jù)庫類型選擇對應SQL語句

    這篇文章主要介紹了mybatis?mapper.xml中如何根據(jù)數(shù)據(jù)庫類型選擇對應SQL語句,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01

最新評論

台山市| 新源县| 吉木乃县| 石嘴山市| 什邡市| 株洲县| 武安市| 濮阳县| 阜城县| 崇仁县| 西乡县| 樟树市| 平凉市| 冷水江市| 北川| 巨野县| 北碚区| 浮山县| 磐石市| 从化市| 买车| 长沙市| 昂仁县| 兴和县| 全椒县| 襄城县| 桂阳县| 迭部县| 佳木斯市| 上饶县| 龙泉市| 岑溪市| 博白县| 江门市| 利川市| 新余市| 胶州市| 武义县| 济宁市| 长沙县| 公主岭市|