Java實(shí)現(xiàn)對象復(fù)制的方法實(shí)例
一、概念
1.淺復(fù)制:復(fù)制出來的對象中的變量(包括基本類型和字符串)和原來的對象的值都相同,但是引用對象仍然指向原來的對象。
2.深復(fù)制:復(fù)制出來的對象中的變量(包括基本類型和字符串)和原來的對象的值都相同,引用對象也會(huì)指向復(fù)制出來的對象。
淺復(fù)制與深復(fù)制的不同之處就在于深復(fù)制還會(huì)復(fù)制對象的引用對象。
二、實(shí)現(xiàn)復(fù)制
1.使用Cloneable接口實(shí)現(xiàn)對象的復(fù)制
⑴淺復(fù)制
代碼如下
public class Food { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
public class Animal implements Cloneable { // 動(dòng)物名 private String name; // 食物 private Food food; public String getName() { return name; } public void setName(String name) { this.name = name; } public Food getFood() { return food; } public void setFood(Food food) { this.food = food; } public Animal clone() { Animal animal = null; try { animal = (Animal) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return animal; } }
public class TestCopy { public static void main(String[] args) { Food food = new Food(); food.setName("草"); Animal animal = new Animal(); animal.setName("羊"); animal.setFood(food); Animal animal2 = animal.clone(); System.out.println("animal動(dòng)物名:"+animal.getName()); System.out.println("animal食物名:"+animal.getFood().getName()); System.out.println("animal2動(dòng)物名:"+animal2.getName()); System.out.println("animal2食物名:"+animal2.getFood().getName()); } }
打印結(jié)果是
animal動(dòng)物名:羊
animal食物名:草
animal2動(dòng)物名:羊
animal2食物名:草
此時(shí)已成功的實(shí)現(xiàn)了復(fù)制,但是這只是淺復(fù)制,引用對象Food并沒有被復(fù)制。
驗(yàn)證代碼
public class TestCopy { public static void main(String[] args) { Food food = new Food(); food.setName("草"); Animal animal = new Animal(); animal.setName("羊"); animal.setFood(food); Animal animal2 = animal.clone(); System.out.println("animal動(dòng)物名:"+animal.getName()); System.out.println("animal食物名:"+animal.getFood().getName()); System.out.println("animal2動(dòng)物名:"+animal2.getName()); System.out.println("animal2食物名:"+animal2.getFood().getName()); //改變animal中food對象的值 food.setName("樹葉"); System.out.println("animal動(dòng)物名:"+animal.getName()); System.out.println("animal食物名:"+animal.getFood().getName()); System.out.println("animal2動(dòng)物名:"+animal2.getName()); System.out.println("animal2食物名:"+animal2.getFood().getName()); } }
打印結(jié)果是
animal動(dòng)物名:羊
animal食物名:草
animal2動(dòng)物名:羊
animal2食物名:草
animal動(dòng)物名:羊
animal食物名:樹葉
animal2動(dòng)物名:羊
animal2食物名:樹葉
結(jié)果證明改變animal中的引用對象food,同時(shí)也改變了animal2中的引用對象food,說明animal和animal2的引用對象food是同一對象。
⑵深復(fù)制
要實(shí)現(xiàn)深復(fù)制,就必須同時(shí)復(fù)制引用對象,引用對象需實(shí)現(xiàn)Cloneable接口,F(xiàn)ood修改如下
public class Food implements Cloneable{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Food clone() { Food food = null; try { food = (Food) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return food; } }
Animal修改如下
public class Animal implements Cloneable { // 動(dòng)物名 private String name; // 食物 private Food food; public String getName() { return name; } public void setName(String name) { this.name = name; } public Food getFood() { return food; } public void setFood(Food food) { this.food = food; } public Animal clone() { Animal animal = null; try { animal = (Animal) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } //復(fù)制引用對象 animal.food = food.clone(); return animal; } }
在clone方法中添加了引用對象的復(fù)制
使用上面的main方法測試,打印結(jié)果如下
animal動(dòng)物名:羊
animal食物名:草
animal2動(dòng)物名:羊
animal2食物名:草
animal動(dòng)物名:羊
animal食物名:樹葉
animal2動(dòng)物名:羊
animal2食物名:草
結(jié)果證明animal和animal2的引用對象food已經(jīng)不是同一對象了,此時(shí)成功地實(shí)現(xiàn)了深復(fù)制。
2.使用序列化(Serializable接口)實(shí)現(xiàn)對象的復(fù)制
使用Cloneable接口每個(gè)類都需要寫clone方法,工作量是很大的,我們可以使用序列化來實(shí)現(xiàn)對象的拷貝,這需要對象實(shí)現(xiàn)java.io.Serializable接口。
將上面的Animal和Food修改一下
import java.io.Serializable; public class Food implements Serializable{ private static final long serialVersionUID = 6466656398591229036L; private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
import java.io.Serializable; public class Animal implements Serializable { private static final long serialVersionUID = -8424013303049171827L; // 動(dòng)物名 private String name; // 食物 private Food food; public String getName() { return name; } public void setName(String name) { this.name = name; } public Food getFood() { return food; } public void setFood(Food food) { this.food = food; } }
再寫一個(gè)復(fù)制的工具類
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class CopyUtil { @SuppressWarnings("unchecked") public static <T extends Serializable> T clone(T obj) { T cloneObj = null; ByteArrayOutputStream baos = null; ByteArrayInputStream bais = null; ObjectOutputStream oos = null; ObjectInputStream ois = null; try { // 序列化 baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(obj); // 反序列化,生成新對象 bais = new ByteArrayInputStream( baos.toByteArray()); ois = new ObjectInputStream(bais); cloneObj = (T) ois.readObject(); } catch (Exception e) { e.printStackTrace(); } finally{ try { if(oos!=null){ oos.close(); } if(baos!=null){ baos.close(); } if(ois!=null){ ois.close(); } if(bais!=null){ bais.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return cloneObj; } }
測試代碼
public class TestCopy { public static void main(String[] args) { Food food = new Food(); food.setName("草"); Animal animal = new Animal(); animal.setName("羊"); animal.setFood(food); Animal animal2 = CopyUtil.clone(animal); System.out.println("animal動(dòng)物名:"+animal.getName()); System.out.println("animal食物名:"+animal.getFood().getName()); System.out.println("animal2動(dòng)物名:"+animal2.getName()); System.out.println("animal2食物名:"+animal2.getFood().getName()); //改變animal中food對象的值 food.setName("樹葉"); System.out.println("animal動(dòng)物名:"+animal.getName()); System.out.println("animal食物名:"+animal.getFood().getName()); System.out.println("animal2動(dòng)物名:"+animal2.getName()); System.out.println("animal2食物名:"+animal2.getFood().getName()); } }
打印結(jié)果如下
animal動(dòng)物名:羊
animal食物名:草
animal2動(dòng)物名:羊
animal2食物名:草
animal動(dòng)物名:羊
animal食物名:樹葉
animal2動(dòng)物名:羊
animal2食物名:草
利用序列化成功的實(shí)現(xiàn)了深復(fù)制。
到此這篇關(guān)于Java實(shí)現(xiàn)對象復(fù)制的方法實(shí)例的文章就介紹到這了,更多相關(guān)Java對象復(fù)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何用ObjectMapper將復(fù)雜Map轉(zhuǎn)換為實(shí)體類
這篇文章主要介紹了如何用ObjectMapper將復(fù)雜Map轉(zhuǎn)換為實(shí)體類的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Java使用IOC控制反轉(zhuǎn)的三種設(shè)計(jì)模式詳解
這篇文章主要為大家詳細(xì)介紹了Java使用IOC控制反轉(zhuǎn)的三種設(shè)計(jì)模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10Spring MVC之mvc:resources如何處理靜態(tài)資源
這篇文章主要介紹了Spring MVC之mvc:resources如何處理靜態(tài)資源問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03Java 并發(fā)編程ArrayBlockingQueue的實(shí)現(xiàn)
這篇文章主要介紹了Java 并發(fā)編程ArrayBlockingQueue的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02Spring Boot集成netty實(shí)現(xiàn)客戶端服務(wù)端交互示例詳解
這篇文章主要給大家介紹了關(guān)于Spring Boot集成netty實(shí)現(xiàn)客戶端服務(wù)端交互的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-12-12SpringMVC實(shí)戰(zhàn)案例RESTFul實(shí)現(xiàn)添加功能
這篇文章主要為大家介紹了SpringMVC實(shí)戰(zhàn)案例RESTFul實(shí)現(xiàn)添加功能詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05利用MyBatis實(shí)現(xiàn)條件查詢的方法匯總
這篇文章主要給大家介紹了關(guān)于利用MyBatis實(shí)現(xiàn)條件查詢的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者使用MyBatis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08