吊打面试官深拷贝浅拷贝引用拷贝的区别
#头条创作挑战赛#引用拷贝
引用拷贝: 引用拷贝不会在堆上创建一个新的对象,只 会在栈上生成一个新的引用地址,最终指向依然是 堆上的同一个对象 。 //实体类 public class Person{ public String name;//姓名 public int height;//身高 public StringBuilder something; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public StringBuilder getSomething() { return something; } public void setSomething(StringBuilder something) { this.something = something; } public Person(String name, int height, StringBuilder something) { this.name = name; this.height = height; this.something = something; } } //测试类 public class copyTest { public static void main(String[] args) { Person p1 = new Person("小张", 180, new StringBuilder("今天天气很好")); Person p2 = p1; System.out.println("对象是否相等:"+ (p1 == p2)); System.out.println("p1 属性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething()); System.out.println("p2 属性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething()); // change p1.name="小王"; p1.height = 200; p1.something.append(",适合出去玩"); System.out.println("...after p1 change...."); System.out.println("p1 属性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething()); System.out.println("p2 属性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething()); } }
结果: 对象是否相等:true
p1 属性值=小张,180,今天天气很好
p2 属性值=小张,180,今天天气很好
...after p1 change....
p1 属性值=小王,200,今天天气很好,适合出去玩
p2 属性值=小王,200,今天天气很好,适合出去玩
before change:
after change:
我们可以看出 由于2个引用p1,p2 都是指向堆中同一个对象,所以2个对象是相等的,修改了对象p1,会影响到对象p2 需要注意的 name属性,虽然她是引用类型,但她同时也是String类型,不可变,对其修改,JVM会默认在堆上创建新的内存空间,再重新赋值 int weight=180; 是成员变量,存放在堆中,不是所有的基本类型变量 都存放在JVM栈中
注意与这篇文章得区分开来 https://mp.weixin.qq.com/s/6qRspyLAsoBxttGwGtxsAA,int num1 = 10;是基本类型的局部变量, 存放在栈中 浅拷贝
浅拷贝 :浅拷贝会在堆上创建一个新的对象, 新对象和原对象不等,但是新对象的属性和老对象相同 。 其中: 如果属性是基本类型(int,double,long,boolean等),拷贝的就是基本类型的值。 如果属性是引用类型(除了基本类型都是引用类型),拷贝的就是引 数据类型变量的地址值, 对于引 类型变量指向的堆中的对象不会拷贝。
如何实现浅拷贝呢?也很简单, 就是在需要拷贝的类上实现Cloneable接口并重写其clone()方法 。 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
在使用的时候直接调用类的clone()方法即可 //实体类 继承Cloneable public class Person implements Cloneable{ public String name;//姓名 public int height;//身高 public StringBuilder something; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public StringBuilder getSomething() { return something; } public void setSomething(StringBuilder something) { this.something = something; } public Person(String name, int height, StringBuilder something) { this.name = name; this.height = height; this.something = something; } @Override public Person clone() throws CloneNotSupportedException { return (Person) super.clone(); } } //测试类 public class shallowCopyTest { public static void main(String[] args) throws CloneNotSupportedException { Person p1 = new Person("小张", 180, new StringBuilder("今天天气很好")); Person p2 = p1.clone(); System.out.println("对象是否相等:"+ (p1 == p2)); System.out.println("p1 属性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething()); System.out.println("p2 属性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething()); // change p1.setName("小王"); p1.setHeight(200); p1.getSomething().append(",适合出去玩"); System.out.println("...after p1 change...."); System.out.println("p1 属性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething()); System.out.println("p2 属性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething()); } }
结果: 对象是否相等:false
p1 属性值=小张,180,今天天气很好
p2 属性值=小张,180,今天天气很好
...after p1 change....
p1 属性值=小王,200,今天天气很好,适合出去玩
p2 属性值=小张,180,今天天气很好,适合出去玩
before change:
after change:
我们可以看出: 当我们修改对象p1的weight属性时,由于p2的height属性 是直接复制修改前的p1的height属性,所以还是180。 当我们修改对象p1的name属性 时,String name指向一个新的内存空间,但对象p2的name还是指向旧的内存空间,所以对象p2的name属性还是"小张"。 由于对象p1的something属性和对象p2的something属性指向是同一个内存空间,当我们修改对象p1的something属性,会影响到对象p2的something属性,所以对象p2的something属性变为"今天天气很好,适合出去玩"。 深拷贝
深拷贝 :完全拷贝 个对象,在堆上创建一个新的对象,拷贝被拷贝对象的成员变量的值,同时堆中的对象也会拷贝。 需要重写clone方法 @Override public Person clone() throws CloneNotSupportedException { //return (Person) super.clone(); Person person = (Person) super.clone(); person.setSomething( new StringBuilder(person.getSomething()));//单独为引用类型clone return person; }
shallowCopyTest测试类的结果: 对象是否相等:false
p1 属性值=小张,180,今天天气很好
p2 属性值=小张,180,今天天气很好
...after p1 change....
p1 属性值=小王,200,今天天气很好,适合出去玩
p2 属性值=小张,180,今天天气很好
这时候对象p1和对象p2互不干扰了
before change:
after change:
但这样也有个小问题,对象每有一个引用类型,我们都得重写其clone方法,这样会非常麻烦,因此我们还可以借助 序列化 来实现对象的深拷贝 //实体类 继承Cloneable public class Person implements Serializable{ public String name;//姓名 public int height;//身高 public StringBuilder something; ...//省略 getter setter 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(); } } //测试类,这边类名笔者就不换了,在之前的基础上改改 public class shallowCopyTest { public static void main(String[] args) throws Exception { Person p1 = new Person("小张", 180, new StringBuilder("今天天气很好")); Person p2 = (Person)p1.deepClone(); System.out.println("对象是否相等:"+ (p1 == p2)); System.out.println("p1 属性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething()); System.out.println("p2 属性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething()); // change p1.setName("小王"); p1.setHeight(200); p1.getSomething().append(",适合出去玩"); System.out.println("...after p1 change...."); System.out.println("p1 属性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething()); System.out.println("p2 属性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething()); } }
这样也会得到深拷贝的结果 小结引用拷贝: 引用拷贝不会在堆上创建一个新的对象,只 会在栈上生成一个新的引用地址,最终指向依然是 堆上的同一个对象 。 浅拷贝 :浅拷贝会在堆上创建一个新的对象, 新对象和原对象不等,但是新对象的属性和老对象相同 。
其中: 如果属性是基本类型(int,double,long,boolean等),拷贝的就是基本类型的值。 如果属性是引用类型(除了基本类型都是引用类型),拷贝的就是引 数据类型变量的地址值, 对于引 类型变量指向的堆中的对象不会拷贝。
3.深拷贝 :完全拷贝 个对象,在堆上创建一个新的对象,拷贝被拷贝对象的成员变量的值,同时堆中的对象也会拷贝。
本篇文章到这里就结束啦,如果我的文章对你有所帮助,还请帮忙一键三连: 点赞、关注、收藏 ,你的支持会激励我输出更高质量的文章,感谢!
计算机内功、JAVA源码、职业成长、项目实战、面试相关等更多高质量文章,首发于公众号「小牛呼噜噜」,我们下期再见。
高圆圆现身私人聚会,头发出油结绺懒得打理,挠头发愁疑有心事饿了吗?戳右边关注我们,每天给您送上最新出炉的娱乐硬核大餐!4月4日,有网友在社交平台上晒出高圆圆现身私人聚会的照片,一向以端庄优雅形象著称的女神,此次露面却油光满面,状态引起了网
别让看电视成了闹心事在多数人印象中,看电视本是件简单的事情。然而,随着智能电视的普及,看电视这件事变得不那么简单,甚至还有点闹心。一台电视配两个遥控器开机必须先看广告追剧刷综艺要先充值会员不同的节目需
最全!美光公司的恶心事件梳理,反击战一触即发树大招风,大家都知道美国对华为的打压不是一天两天,但是我们对此我们之前好像并没有采取什么直接的措施去应对这样的事情,没有看到是就代表没有嘛?挖掘美光的历史,就不难看出,美光不只是一
BBA霸榜高端轿车背后的扎心事实电车高端化并不成功BBA霸榜高端轿车背后的扎心事实电车高端化并不成功近年来,随着环保意识的提高和新能源汽车的普及,电动轿车开始逐渐进入高端市场。一些电动汽车品牌不断推出高端车型,试图与传统高端轿车品
自闭症孩子眼中的世界是什么样的?无法感同身受,却可以尝试了解马上就到了世界孤独症日了,2023年4月2日是他们的节日。那星星的孩子在什么样的世界,这是许多人想知道。都说自闭症的孩子是星星的孩子,与我们普通人不在一个世界,他们无法理解我们的行
除了自渡,他人爱莫能助人生在世,不管你的生活多么糟糕,总有那么一个人能让你笑得开怀。在人生的旅途中,我们会遇到很多困难和挫折,这些困难和挫折有时是我们自己造成的,有时却是别人造成的。当遇到困难时,我们可
以太坊在产生的网络费用中主导其区块链兄弟以太坊网络在产生的费用方面远远领先于其区块链同行。该指标反映了它的持续采用。4月10日,区块链数据公司TokenTerminal报告了过去六个月的顶级网络费用生成器。毫不奇怪,以太
房地产也来投资医疗器械,能成?去年8月,联影医疗上市一事传遍了整个医疗圈,但鲜为人知的是,这家国产替代浪潮中的高端医疗设备企业头号种子背后,还有一家房地产CVC的影子。2018年初,保利集团旗下的保利资本计划进
一季度CPI同比上涨1。3物价继续保持平稳运行4月11日,国家统计局发布数据显示,3月份全国居民消费价格指数(CPI)同比上涨0。7,环比下降0。3工业生产者出厂价格指数(PPI)同比下降2。5,环比持平。一季度平均,CPI比
张掖甘州五链招商促发展原标题张掖甘州五链招商促发展图为张掖国家玉米种子产业园施工现场。甘州区委宣传部供图中新网甘肃新闻4月10日电(刘枫冯杰)争分夺秒抓建设铆足干劲赶进度连日来,在张掖市甘州区神农珍稀菇
融创复牌在望,孙宏斌再雄起?寒气之后,终迎暖流。对融创中国的购房者来说,刚刚过去的3月,各种消息扑面而来,让人应接不暇而又五味杂陈。3月23日,融创中国发布盈利警告,毫不隐蔽地公布2022年预亏270亿280