内功心法 -- Java中的深拷贝和浅拷贝
写在前面的话:读书破万卷,编码如有神
--------------------------------------------------------------------
这篇博客主要来谈谈"Java中的深拷贝和浅拷贝"的相关知识,主要内容包括:
1.概述
2.复制对象 or 复制引用
3.深拷贝 or 浅拷贝
--------------------------------------------------------------------
1、概述
clone顾名思义就是克隆的意思,在Java语言中clone方法被调用会复制对象。所谓的复制对象,首先要分配一个和源对象同样大小的内存空间,在这个内存空间中创建一个新的对象。那么在Java语言中,有几种方式可以创建对象呢?
方法一: 使用new操作符创建一个对象
方法二: 使用clone方法克隆一个对象
那么上面这两种方式有什么相同和不同呢? new操作符的本意是分配内存,程序执行到new操作符时,首先去看看new操作符后面的数据类型,因为知道了数据类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把它的引用(地址)发布到外部,在外部就可以使用这个引用操作这个对象了。而clone在第一步是和new操作符相似的,都是进行内存空间的分配,调用clone方法时分配的内存和源对象(即调用clone方法的对象)相同。然后再使用原对象中对应的各个域填充新对象的域,填充完成之后clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。
2、复制对象 or 复制引用
在Java中,以下类似的代码非常常见:
public class Student implements Cloneable{ private int StuId;
private String StuName;
private int StuAge; public Student(int stuId, String stuName, int stuAge) {
super();
StuId = stuId;
StuName = stuName;
StuAge = stuAge;
} @Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
Student stu1 = new Student(0,"zhangsan",20);
Student stu2 = stu1; System.out.println("stu1 = " + stu1);
System.out.println("stu2 = " + stu2);
}
} 运行结果:
stu1 = Student@3c635421
stu2 = Student@3c635421
从运行的结果可以看出:打印的地址值是一样的,既然地址都是一样的,那么肯定是同一个对象。stu1和stu2只是引用而已,它们都指向了一个相同的对象Student(0,"zhangsan",20);可以把这种现象叫做引用的复制。执行完上面的代码之后,内存中的情况如下图:
而下面的代码是真正的实现了克隆一个对象:
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
Student stu3 = new Student(1,"lisi",20);
Student stu4 = (Student) stu3.clone();
System.out.println("stu3 = " + stu3);
System.out.println("stu4 = " + stu4);
}
} 运行结果:
stu3 = Student@7bc2f501
stu4 = Student@3c635421
从打印的结果可以看出,两个对象的地址是不同的,也就是说创建了新的对象,而不是把源对象的地址赋给了一个新的引用变量。
执行完以上代码后,内存中的情况如下图:
3、深拷贝 or 浅拷贝
在上面的示例代码中,Student中有三个成员变量,分别是StuId、StuName、StuAge,其中StuName是String类型,StuId和StuAge是int类型。由于StuId和StuAge是基本数据类型,那么对它们的拷贝没有什么疑议,直接将一个4字节的整数值拷贝过来就可以了。但是StuName是String类型,它只是一个引用,指向一个真正的String对象,那么对它的拷贝分为两种方式: 直接将源对象中的StuName的引用值拷贝给新对象的StuName字段,或者是根据原Student对象中的StuName指向的字符串对象创建一个新的相同的字符串对象,将这个新字符串对象的引用赋值给新拷贝的Student对象的StuName字段。这两种拷贝方式分别是浅拷贝和深拷贝。
深拷贝和浅拷贝的原理如下图所示:
下面通过代码进行验证,如果两个Student对象的StuName的地址值相同,说明两个对象的StuName都指向了同一个String对象,也就是浅拷贝;而如果两个对象的StuName的地址值不同,那么就说明指向不同的String对象,也就是在拷贝Student对象的时候,同时拷贝了StuName引用的对象,也就是深拷贝,代码如下:
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
Student stu1 = new Student(0,"zhangsan",20);
Student stu2 = (Student) stu1.clone(); System.out.println("stu1 = " + stu1);
System.out.println("stu2 = " + stu2); System.out.println("stu1.StuName == stu2.StuName : " + (stu1.getStuName()==stu2.getStuName()));
}
} 运行结果:
stu1 = Student@1df0a2a0
stu2 = Student@2144c5bb
stu1.StuName == stu2.StuName : true
从运行结果可以看出,Object中默认的的clone方法执行的是浅拷贝。
内功心法 -- Java中的深拷贝和浅拷贝的更多相关文章
- 浅谈Java中的深拷贝和浅拷贝(转载)
浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...
- 浅谈Java中的深拷贝和浅拷贝
转载: 浅谈Java中的深拷贝和浅拷贝 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(bool ...
- Java中的深拷贝和浅拷贝
1.浅拷贝与深拷贝概念 (1)浅拷贝(浅克隆) 浅拷贝又叫浅复制,将对象中的所有字段复制到新的对象(副本)中.其中,值类型字段(java中8中原始类型)的值被复制到副本中后,在副本中的修改不会影响到源 ...
- java中的深拷贝与浅拷贝
Java中对象的创建 clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象.所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象.那 ...
- Java中的深拷贝和浅拷贝(转载)
深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java.虽然java自动管理对象的回收,但对于深拷贝(深复 ...
- java基础(十七)----- 浅谈Java中的深拷贝和浅拷贝 —— 面试必问
假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short, ...
- 浅析Java中的深拷贝和浅拷
浅析Java中的深拷贝和浅拷贝 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: in ...
- **Python中的深拷贝和浅拷贝详解
Python中的深拷贝和浅拷贝详解 这篇文章主要介绍了Python中的深拷贝和浅拷贝详解,本文讲解了变量-对象-引用.可变对象-不可变对象.拷贝等内容. 要说清楚Python中的深浅拷贝,需要 ...
- C语言中的深拷贝和浅拷贝
//C语言中的深拷贝和浅拷贝 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #inc ...
随机推荐
- gtk
GTK官网:www.gtk.org sudo apt-get install build-essential 安装GTK开发套件: sudo apt-get install libgtk2.0-dev ...
- 在阿里云ECS(CentOS6.5)上安装mysql
首先查看服务器上是否已经安装过mysql 命令: rpm -qa | grep mysql 结果: 可以看到ECS上已经有mysql-libs这个包了.这并不影响安装. 查看yum服务器上提供的mys ...
- 组织Golang代码
本月初golang官方blog(需要自己搭梯子)上发布了一篇文章,简要介绍了近几个月Go在一 些技术会议上(比如Google I/O.Gopher SummerFest等)的主题分享并伴有slide链 ...
- “&”详解
1.引用 引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样. &作为引用的时候,必须在定义时候就进行初始化,若不进行初始化则会编译报错. 2.取地址 &作为取地 ...
- 微信小程序之----生命周期
在app.js的app()中注册程序 在页面.js中的Page({})中注册页面. 执行效果:
- CastleWindsor 使用说明
1.引用DLL Castle.Core.dll 和Castle.Windsor.dll 2. 引用命名空间 using Castle.MicroKernel.Resolvers.Specialize ...
- MongoDB升级教程
1.排序 sort()方法:其中 1 为升序排列,而-1是用于降序排列. db.col.find({},{"title":1,_id:0}).sort({"likes&q ...
- WebForm和MVC中都可以使用的路由
1.在global.asax void Application_Start(object sender, EventArgs e) { // 在应用程序启动时运行的代码 // RouteConfig. ...
- JAVA-Unit01: 数据库原理 、 SQL(DDL、DML)
Unit01: 数据库原理 . SQL(DDL.DML) SQL语句是不区分大小写的,但是行业里习惯将关键字与分关键字用大小写岔开以提高可读性. SELECT SYSDATE FROM dual DD ...
- UVa 10306 - e-Coins
题目大意:现在有一种新型货币,它的价值分为传统价值x和IT价值y,价值计算方式为sqrt(x*x+y*y),现给一些类型的货币和要达到的目标价值,计算达到目标所需的最少货币数目.注意计算方法是sqrt ...