电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術(shù)文章
文章詳情頁

Java的深拷貝與淺拷貝的幾種實現(xiàn)方式

瀏覽:3日期:2022-08-17 17:04:25
1、介紹

關(guān)于Java的深拷貝和淺拷貝,簡單來說就是創(chuàng)建一個和已知對象一模一樣的對象。可能日常編碼過程中用的不多,但是這是一個面試經(jīng)常會問的問題,而且了解深拷貝和淺拷貝的原理,對于Java中的所謂值傳遞或者引用傳遞將會有更深的理解。

2、淺拷貝

淺拷貝就是獲得拷貝對象的引用,而不是正真意義上的拷貝一個對象,例如

A a = new A(); A b = a;

此時引用變量a和b 同時指向了同一個堆中的內(nèi)存空間,變量b只是復(fù)制了實例A的引用地址,并不是重新在堆中開辟了一個新的空間位置,來完整的復(fù)制實例A 如圖

Java的深拷貝與淺拷貝的幾種實現(xiàn)方式

3、深拷貝

深拷貝則是拷貝了源對象的所有值,所以即使源對象的值發(fā)生變化時,拷貝對象的值也不會改變。深拷貝則是真正意義上的拷貝,如圖

Java的深拷貝與淺拷貝的幾種實現(xiàn)方式

4、深拷貝和淺拷貝的區(qū)別

簡單來說就是一句話: 深拷貝和淺拷貝最根本的區(qū)別在于是否真正獲取一個對象的復(fù)制實體,而不是引用。

5、淺拷貝的實現(xiàn)

首先,我們定義一下需要拷貝的簡單對象。

public class Student{ private String name; private int age; private String sex; }public class School { private String schoolName; private int stuNums; private Student stu;}

如上述代碼,我們定義了一個Student學(xué)生類,包含name姓名,和age年齡,sex性別,而是另一個School類,包含schoolName學(xué)校名稱和stuNums學(xué)生數(shù)量以及Student學(xué)生,其中Student并不是字符串,而是一個Student類。接下來我們將詳細(xì)描述如何簽拷貝School對象。我們看如下這段代碼:

public class Student{ private String name; private int age; private String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return 'Student [name=' + name + ', age=' + age + ', sex=' + sex + ']'; }}

public class School implements Cloneable{ private String schoolName; private int stuNums; private Student stu; public String getSchoolName() { return schoolName; } public void setSchoolName(String schoolName) { this.schoolName = schoolName; } public int getStuNums() { return stuNums; } public void setStuNums(int stuNums) { this.stuNums = stuNums; } public Student getStu() { return stu; } public void setStu(Student stu) { this.stu = stu; } @Override protected School clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return (School)super.clone(); } @Override public String toString() { return 'School [schoolName=' + schoolName + ', stuNums=' + stuNums + ', stu=' + stu + ']'; }}

這是一個我們要進(jìn)行賦值的原始類 School。下面我們產(chǎn)生一個 School對象,并調(diào)用其 clone 方法復(fù)制一個新的對象。注意:調(diào)用對象的 clone 方法,必須要讓類實現(xiàn) Cloneable 接口,并且覆寫 clone 方法。

public class TestClone { public static void main(String[] args) throws CloneNotSupportedException { //創(chuàng)建初始的School對象 School s1 = new School(); s1.setSchoolName('xx大學(xué)'); s1.setStuNums(2000); Student stu1 = new Student(); stu1.setAge(20); stu1.setName('肉丁'); stu1.setSex('女'); s1.setStu(stu1); School s2 = s1.clone(); //調(diào)用重寫的clone方法,clone出一個新的school---s2 System.out.println('s1: '+s1+' s1的hashcode:'+s1.hashCode()+' s1中stu1的hashcode:'+s1.getStu().hashCode()); System.out.println('s2: '+s2+' s2的hashcode:'+s2.hashCode()+' s2中stu1的hashcode:'+s2.getStu().hashCode());//System.out.println(s1.getStu().getAge()==s2.getStu().getAge()); System.out.println('----------------------------'); System.out.println('修改克隆出來的對象'); Student student2 = s2.getStu(); student2.setAge(21); student2.setName('斌'); s2.setStu(student2); System.out.println('s1: '+s1+' s1的hashcode:'+s1.hashCode()+' s1中stu1的hashcode:'+s1.getStu().hashCode()); System.out.println('s2: '+s2+' s2的hashcode:'+s2.hashCode()+' s2中stu1的hashcode:'+s2.getStu().hashCode());//System.out.println(s1.getStu().getAge()==s2.getStu().getAge()); }}

我們查看輸出的結(jié)果

s1: School [schoolName=xx大學(xué), stuNums=2000, stu=Student [name=肉丁, age=20, sex=女]] s1的hashcode:500977346 s1中stu1的hashcode:20132171s2: School [schoolName=xx大學(xué), stuNums=2000, stu=Student [name=肉丁, age=20, sex=女]] s2的hashcode:186370029 s2中stu1的hashcode:20132171修改克隆出來的對象s1: School [schoolName=xx大學(xué), stuNums=2000, stu=Student [name=斌, age=21, sex=女]] s1的hashcode:500977346 s1中stu1的hashcode:20132171s2: School [schoolName=xx大學(xué), stuNums=2000, stu=Student [name=斌, age=21, sex=女]] s2的hashcode:186370029 s2中stu1的hashcode:20132171

首先看原始類 School 實現(xiàn) Cloneable 接口,并且覆寫 clone 方法,它還有三個屬性,一個引用類型 String定義的 schoolName,一個基本類型 int定義的 stuNums,還有一個引用類型 Student,這是一個自定義類,這個類也包含三個屬性 name、age和 sex。

接著看測試內(nèi)容,首先我們創(chuàng)建一個School類的對象s1 ,其schoolName為xx大學(xué),stuNums為2000,學(xué)生類Stundet三個屬性為 20、肉丁和女。接著我們調(diào)用 clone() 方法復(fù)制另一個對象 s2,接著打印這兩個對象的內(nèi)容。

從第 2 行和第 5 行打印結(jié)果:

s1的hashcode:500977346 s2的hashcode:186370029

可以看出這是兩個不同的對象。

從第 1 行和第 4 行打印的對象內(nèi)容看,原對象 s1 和克隆出來的對象 s2 內(nèi)容完全相同。

代碼中我們只是更改了克隆對象 s2 的屬性Student 為斌、21、女(原對象 s1 是肉丁、20、女) ,但是從第 8 行和第 11 行打印結(jié)果來看,原對象 s1 和克隆對象 s2 的 Student屬性都被修改了。

也就是說對象 School的屬性 Student,經(jīng)過 clone 之后,其實只是復(fù)制了其引用,他們指向的還是同一塊堆內(nèi)存空間,當(dāng)修改其中一個對象的屬性 Student,另一個也會跟著變化。

6、深拷貝的實現(xiàn)

深拷貝的方式有很多種,文中我們將介紹三種方式

方法一 構(gòu)造函數(shù) 方法二 重載clone()方法 方法三Serializable序列化6.1、構(gòu)造函數(shù)

public void constructorCopy() { Student student = new Student ('小李',21,'男'); School school = new School ('xx大學(xué)',100, student); // 調(diào)用構(gòu)造函數(shù)時進(jìn)行深拷貝 School copySchool = new School (school.getSchoolName(),school.getStuNums(), new Student(student.getName(), student.getAge(),student.getSex())); // 修改源對象的值 copySchool .getStudent().setSex('女'); // 檢查兩個對象的值不同 System.out.println(school.hashCode()==school2.hasCode()) }6.2、重載clone()方法

Object父類有個clone()的拷貝方法,不過它是protected類型的,我們需要重寫它并修改為public類型。除此之外,子類還需要實現(xiàn)Cloneable接口來告訴JVM這個類是可以拷貝的。讓我們還是看之前的School代碼

public class School implements Cloneable{ private String schoolName; private int stuNums; private Student stu; public String getSchoolName() { return schoolName; } public void setSchoolName(String schoolName) { this.schoolName = schoolName; } public int getStuNums() { return stuNums; } public void setStuNums(int stuNums) { this.stuNums = stuNums; } public Student getStu() { return stu; } public void setStu(Student stu) { this.stu = stu; } @Override protected School clone() throws CloneNotSupportedException { School school = (School) super.clone(); school.stu = (Student) stu.clone(); return school; } @Override public String toString() { return 'School [schoolName=' + schoolName + ', stuNums=' + stuNums + ', stu=' + stu + ']'; }}

public class Student implements Cloneable{ private String name; private int age; private String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return 'Student [name=' + name + ', age=' + age + ', sex=' + sex + ']'; } @Override protected Student clone() throws CloneNotSupportedException { return (Student)super.clone(); }}

我們查看輸出的結(jié)果

s1: School [schoolName=xx大學(xué), stuNums=2000, stu=Student [name=肉丁, age=20, sex=女]]s1的hashcode:500977346 s1中stu1的hashcode:20132171s2: School [schoolName=xx大學(xué), stuNums=2000, stu=Student [name=肉丁, age=20, sex=女]] s2的hashcode:186370029 s2中stu1的hashcode:2094548358修改克隆出來的對象s1: School [schoolName=xx大學(xué), stuNums=2000, stu=Student [name=肉丁, age=20, sex=女]] s1的hashcode:500977346 s1中stu1的hashcode:20132171s2: School [schoolName=xx大學(xué), stuNums=2000, stu=Student [name=斌, age=21, sex=女]] s2的hashcode:186370029 s2中stu1的hashcode:2094548358

需要注意的是,super.clone()其實是淺拷貝,所以在重寫School類的clone()方法時,Student對象需要調(diào)用stu.clone()重新賦值。查看第 2 行和第 5 行

s1的hashcode:500977346 s2的hashcode:186370029

查看第 3 行和第 6 行

s1中stu1的hashcode:20132171s2中stu1的hashcode:2094548358

通過結(jié)果發(fā)現(xiàn)重新復(fù)制的對象s2和s1的hashCode不同,并且s1.stu與s2.stu2的hashCode也不同,由此證明復(fù)制的新的對象和原本的對象指向的不是同一個一個對象,意味著堆內(nèi)存中存在兩個School實例

6.3、Serializable序列化

我們看如下的代碼

import java.io.Serializable;public class User implements Serializable { private String name; private Address2 address; public User(String name, Address2 address) { this.name = name; this.address = address; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Address2 getAddress() { return address; } public void setAddress(Address2 address) { this.address = address; } public Object deepClone() throws Exception { // 序列化 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); // 反序列化 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); }}

import java.io.Serializable;public class Address2 implements Serializable { private String city; private String country; public Address2(String city, String country) { this.city = city; this.country = country; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } @Override public String toString() { return 'Address2{' +'city=’' + city + ’’’ +', country=’' + country + ’’’ +’}’; }}

注意 要使用序列化的方式來復(fù)制對象 對象需要繼承Serializable接口,接下來我們查看測試類

public static void main(String[] args) throws Exception { Address2 address = new Address2('大同', '中國'); User user = new User('yznl', address); User user2 = (User) user.deepClone(); System.out.println(user.toString()); System.out.println(user2.toString()); }

結(jié)果如下:

277630005,1915503092

通過比較user對象和克隆的user2對象的hashCode發(fā)現(xiàn),也是不同的對象

到此這篇關(guān)于Java的深拷貝與淺拷貝的幾種實現(xiàn)方式的文章就介紹到這了,更多相關(guān)Java 深拷貝與淺拷貝內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 蜘蛛车-高空作业平台-升降机-高空作业车租赁-臂式伸缩臂叉装车-登高车出租厂家 - 普雷斯特机械设备(北京)有限公司 | 税筹星_灵活用工平台_企业财务顾问_财税法薪综合服务平台 | 碳纤维布-植筋胶-灌缝胶-固特嘉加固材料公司 | 乐之康护 - 专业护工服务平台,提供医院陪护-居家照护-居家康复 | 全屋整木定制-橱柜,家具定制-四川峨眉山龙马木业有限公司 | 细胞染色-流式双标-试剂盒免费代做-上海研谨生物科技有限公司 | 杭州中央空调维修_冷却塔/新风机柜/热水器/锅炉除垢清洗_除垢剂_风机盘管_冷凝器清洗-杭州亿诺能源有限公司 | 帽子厂家_帽子工厂_帽子定做_义乌帽厂_帽厂_制帽厂_帽子厂_浙江高普制帽厂 | 合肥网带炉_安徽箱式炉_钟罩炉-合肥品炙装备科技有限公司 | 西点培训学校_法式西点培训班_西点师培训_西点蛋糕培训-广州烘趣西点烘焙培训学院 | 机床主轴维修|刀塔维修|C轴维修-常州翔高精密机械有限公司 | LED太阳能中国结|发光红灯笼|灯杆造型灯|节日灯|太阳能灯笼|LED路灯杆装饰造型灯-北京中海轩光电 | 依维柯自动挡房车,自行式国产改装房车,小型房车价格,中国十大房车品牌_南京拓锐斯特房车 - 南京拓锐斯特房车 | 本安接线盒-本安电路用接线盒-本安分线盒-矿用电话接线盒-JHH生产厂家-宁波龙亿电子科技有限公司 | 东莞爱加真空科技有限公司-进口真空镀膜机|真空镀膜设备|Polycold维修厂家 | 烘箱-工业烘箱-工业电炉-实验室干燥箱 - 苏州华洁烘箱制造有限公司 | 直线模组_滚珠丝杆滑台_模组滑台厂家_万里疆科技 | 智能汉显全自动量热仪_微机全自动胶质层指数测定仪-鹤壁市科达仪器仪表有限公司 | 油冷式_微型_TDY电动滚筒_外装_外置式电动滚筒厂家-淄博秉泓机械有限公司 | 天津试验仪器-电液伺服万能材料试验机,恒温恒湿标准养护箱,水泥恒应力压力试验机-天津鑫高伟业科技有限公司 | 压接机|高精度压接机|手动压接机|昆明可耐特科技有限公司[官网] 胶泥瓷砖胶,轻质粉刷石膏,嵌缝石膏厂家,腻子粉批发,永康家德兴,永康市家德兴建材厂 | 污水处理设备,一体化泵站,一体化净水设备-「梦之洁环保设备厂家」 | 污泥烘干机-低温干化机-工业污泥烘干设备厂家-焦作市真节能环保设备科技有限公司 | 贵州科比特-防雷公司厂家提供贵州防雷工程,防雷检测,防雷接地,防雷设备价格,防雷产品报价服务-贵州防雷检测公司 | 杰福伦_磁致伸缩位移传感器_线性位移传感器-意大利GEFRAN杰福伦-河南赉威液压科技有限公司 | elisa试剂盒价格-酶联免疫试剂盒-猪elisa试剂盒-上海恒远生物科技有限公司 | 安全光栅|射频导纳物位开关|音叉料位计|雷达液位计|两级跑偏开关|双向拉绳开关-山东卓信机械有限公司 | 合肥通道闸-安徽车牌识别-人脸识别系统厂家-安徽熵控智能技术有限公司 | 三佳互联一站式网站建设服务|网站开发|网站设计|网站搭建服务商 赛默飞Thermo veritiproPCR仪|ProFlex3 x 32PCR系统|Countess3细胞计数仪|371|3111二氧化碳培养箱|Mirco17R|Mirco21R离心机|仟诺生物 | Q361F全焊接球阀,200X减压稳压阀,ZJHP气动单座调节阀-上海戎钛 | 超声波清洗机_超声波清洗机设备_超声波清洗机厂家_鼎泰恒胜 | 博客-悦享汽车品质生活 | 高通量组织研磨仪-多样品组织研磨仪-全自动组织研磨仪-研磨者科技(广州)有限公司 | 优考试_免费在线考试系统_培训考试系统_题库系统_组卷答题系统_匡优考试 | 低气压试验箱_高低温低气压试验箱_低气压实验箱 |林频试验设备品牌 | 金蝶帐无忧|云代账软件|智能财税软件|会计代账公司专用软件 | 铝合金脚手架厂家-专注高空作业平台-深圳腾达安全科技 | 专业深孔加工_东莞深孔钻加工_东莞深孔钻_东莞深孔加工_模具深孔钻加工厂-东莞市超耀实业有限公司 | 仿清水混凝土_清水混凝土装修_施工_修饰_保护剂_修补_清水混凝土修复-德州忠岭建筑装饰工程 | 杭州代理记账多少钱-注册公司代办-公司注销流程及费用-杭州福道财务管理咨询有限公司 | 铆钉机|旋铆机|东莞旋铆机厂家|鸿佰专业生产气压/油压/自动铆钉机 |