Java實(shí)現(xiàn)對(duì)象復(fù)制的方法實(shí)例
一、概念
1.淺復(fù)制:復(fù)制出來的對(duì)象中的變量(包括基本類型和字符串)和原來的對(duì)象的值都相同,但是引用對(duì)象仍然指向原來的對(duì)象。
2.深復(fù)制:復(fù)制出來的對(duì)象中的變量(包括基本類型和字符串)和原來的對(duì)象的值都相同,引用對(duì)象也會(huì)指向復(fù)制出來的對(duì)象。
淺復(fù)制與深復(fù)制的不同之處就在于深復(fù)制還會(huì)復(fù)制對(duì)象的引用對(duì)象。
二、實(shí)現(xiàn)復(fù)制
1.使用Cloneable接口實(shí)現(xiàn)對(duì)象的復(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ù)制,引用對(duì)象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對(duì)象的值
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中的引用對(duì)象food,同時(shí)也改變了animal2中的引用對(duì)象food,說明animal和animal2的引用對(duì)象food是同一對(duì)象。
⑵深復(fù)制
要實(shí)現(xiàn)深復(fù)制,就必須同時(shí)復(fù)制引用對(duì)象,引用對(duì)象需實(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ù)制引用對(duì)象
animal.food = food.clone();
return animal;
}
}在clone方法中添加了引用對(duì)象的復(fù)制
使用上面的main方法測(cè)試,打印結(jié)果如下
animal動(dòng)物名:羊
animal食物名:草
animal2動(dòng)物名:羊
animal2食物名:草
animal動(dòng)物名:羊
animal食物名:樹葉
animal2動(dòng)物名:羊
animal2食物名:草
結(jié)果證明animal和animal2的引用對(duì)象food已經(jīng)不是同一對(duì)象了,此時(shí)成功地實(shí)現(xiàn)了深復(fù)制。
2.使用序列化(Serializable接口)實(shí)現(xiàn)對(duì)象的復(fù)制
使用Cloneable接口每個(gè)類都需要寫clone方法,工作量是很大的,我們可以使用序列化來實(shí)現(xiàn)對(duì)象的拷貝,這需要對(duì)象實(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);
// 反序列化,生成新對(duì)象
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;
}
}測(cè)試代碼
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對(duì)象的值
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)對(duì)象復(fù)制的方法實(shí)例的文章就介紹到這了,更多相關(guān)Java對(duì)象復(fù)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringMVC實(shí)現(xiàn)文件上傳和下載功能
這篇文章主要為大家詳細(xì)介紹了SpringMVC實(shí)現(xiàn)文件上傳和下載功能 ,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
IntelliJ IDEA設(shè)置代碼的快捷編輯模板Live Templates
今天小編就為大家分享一篇關(guān)于IntelliJ IDEA設(shè)置代碼的快捷編輯模板Live Templates,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-10-10
Spring Boot 3 中 WebFilter 的執(zhí)行順序流程分析
Spring Boot中管理WebFilter順序,默認(rèn)為Integer.MAX_VALUE,需顯式使用@Order或Ordered接口定義優(yōu)先級(jí),請(qǐng)求階段按順序值從小到大執(zhí)行,響應(yīng)階段按從大到小,相同順序值依賴Bean注冊(cè)順序,本文詳細(xì)說明在Spring Boot 3中如何管理這些過濾器的執(zhí)行流程,需要的朋友一起看看吧2025-08-08
使用Springboot搭建OAuth2.0 Server的方法示例
這篇文章主要介紹了使用Springboot搭建OAuth2.0 Server的方法示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08
idea找不到創(chuàng)建package包的選項(xiàng)問題及解決方案
在IntelliJ IDEA中找不到創(chuàng)建package包選項(xiàng)?按照步驟操作即可顯示:右鍵選擇Mark Directory as -> Source Root2026-03-03
Spring應(yīng)用拋出NoUniqueBeanDefinitionException異常的解決方案
這篇文章介紹了解決org.springframework.beans.factory.NoUniqueBeanDefinitionException異常的一些解決方案,從這些解決方案可以看出Spring框架的設(shè)計(jì)精妙,遇見此問題的朋友可以參考下該解決方案2021-06-06

