Java clone() 方法克隆对象——深拷贝与浅拷贝
基本数据类型引用数据类型特点
1、基本数据类型的特点:直接存储在栈(stack)中的数据
2、引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里
引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
深拷贝与浅拷贝特点
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
当把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。
Java clone方法深拷贝与浅拷贝
clone浅拷贝
由CloneDemo类可以看出,没有重写clone方法,对象中的引用数据类型只是复制了该引用数据类型的引用,并没有在内存空间中开辟空间复制该引用数据类型,即对该引用数据类型进行了浅拷贝而不是深拷贝。
package JDKSource.lang;
public class CloneDemo implements Cloneable {
private int num;
private String name;
private Helper helper;
public CloneDemo() {
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Helper getHelper() {
return helper;
}
@Override
public String toString() {
return "CloneDemo{" +
"num=" + num +
", name='" + name + '\'' +
", helper=" + helper +
'}';
}
public void setHelper(Helper helper) {
this.helper = helper;
}
public static class Helper {
public int num;
public Helper(int num) {
this.num = num;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
@Override
public String toString() {
return "Helper{" +
"num=" + num +
'}';
}
}
public static void main(String[] args) throws CloneNotSupportedException {
CloneDemo d1 = new CloneDemo();
d1.setName("Jack");
d1.setNum(10);
d1.setHelper(new Helper(100));
CloneDemo d2 = (CloneDemo) d1.clone();
System.out.println(d1.name == d2.name);
System.out.println(d1.num == d2.num);
System.out.println(d1.helper == d2.helper);
d2.setNum(11);
d2.setName("json");
d2.getHelper().setNum(101);
System.out.println(d1.name);
System.out.println(d1.num);
System.out.println(d1.helper.toString());
System.out.println(d2.name);
System.out.println(d2.num);
System.out.println(d2.helper.toString());
/* Output:
true
true
true
Jack
10
Helper{num=101}
json
11
Helper{num=101}*/
}
}
clone深拷贝
对Helper类和CloneDemo都重写clone方法:
CloneDemo重写clone方法:
@Override
protected CloneDemo clone() throws CloneNotSupportedException {
CloneDemo clone = (CloneDemo1) super.clone();
clone.helper = helper.clone();
return clone;
}
Helper重写clone方法:
@Override
protected Helper clone() throws CloneNotSupportedException {
Helper helper = null;
Helper clone = (Helper) super.clone();
return clone;
}
输出结果:
结果显示,对Helper类和CloneDemo都重写clone方法后,实现了对引用数据类型Helper的深拷贝。
/* Output:
true
true
false
Jack
10
Helper{num=100}
json
11
Helper{num=101}*/
完整代码:
package JDKSource.lang;
public class CloneDemo1 implements Cloneable {
private int num;
private String name;
private Helper helper;
public CloneDemo1() {
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Helper getHelper() {
return helper;
}
@Override
protected CloneDemo1 clone() throws CloneNotSupportedException {
CloneDemo1 clone = (CloneDemo1) super.clone();
clone.helper = helper.clone();
return clone;
}
@Override
public String toString() {
return "CloneDemo{" +
"num=" + num +
", name='" + name + '\'' +
", helper=" + helper +
'}';
}
public void setHelper(Helper helper) {
this.helper = helper;
}
public static class Helper implements Cloneable {
public int num;
public Helper(int num) {
this.num = num;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
@Override
public String toString() {
return "Helper{" +
"num=" + num +
'}';
}
@Override
protected Helper clone() throws CloneNotSupportedException {
Helper helper = null;
Helper clone = (Helper) super.clone();
return clone;
}
}
public static void main(String[] args) throws CloneNotSupportedException {
CloneDemo1 d1 = new CloneDemo1();
d1.setName("Jack");
d1.setNum(10);
d1.setHelper(new Helper(100));
CloneDemo1 d2 = (CloneDemo1) d1.clone();
System.out.println(d1.name == d2.name);
System.out.println(d1.num == d2.num);
System.out.println(d1.helper == d2.helper);
d2.setNum(11);
d2.setName("json");
d2.getHelper().setNum(101);
System.out.println(d1.name);
System.out.println(d1.num);
System.out.println(d1.helper.toString());
System.out.println(d2.name);
System.out.println(d2.num);
System.out.println(d2.helper.toString());
/* Output:
true
true
false
Jack
10
Helper{num=100}
json
11
Helper{num=101}*/
}
}
Java clone() 方法克隆对象——深拷贝与浅拷贝的更多相关文章
- Java 中如何使用clone()方法克隆对象?
java为什么要 对象克隆: 在程序开发时,有时可能会遇到以下情况:已经存在一个对象A,现在需要一个与A对象完全相同的B 对象,并对B 对象的属性值进行修改,但是A 对象原有的属性值不能改变.这时,如 ...
- java对象的克隆以及深拷贝与浅拷贝
一.为什么要使用克隆 在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能 会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也 ...
- 关于Java的Object.clone()方法与对象的深浅拷贝
文章同步更新在个人博客:关于Java的Object.clone()方法与对象的深浅拷贝 引言 在某些场景中,我们需要获取到一个对象的拷贝用于某些处理.这时候就可以用到Java中的Object.clon ...
- Object.clone()方法与对象的深浅拷贝
转载:[https://www.cnblogs.com/nickhan/p/8569329.html] 引言 在某些场景中,我们需要获取到一个对象的拷贝用于某些处理.这时候就可以用到Java中的Obj ...
- javascript对象深拷贝,浅拷贝 ,支持数组
javascript对象深拷贝,浅拷贝 ,支持数组 经常看到讨论c#深拷贝,浅拷贝的博客,最近js写的比较多, 所以也来玩玩js的对象拷贝. 下面是维基百科对深浅拷贝的解释: 浅拷贝 One meth ...
- Java clone方法(下)
1.终于调用的是一个JNI方法,即java本地方法,加高速度 2.使用clone方法,分为浅复制.深复制,这里直接使用网上抄来的案例来说明吧: 说明: 1)为什么我们在派生类中覆盖Object的clo ...
- java对象克隆以及深拷贝和浅拷贝
1.什么是"克隆"? 在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能 会需要一个和A完全相同新对象B,并且此后对B任何改动都不 ...
- JAVA中对象的克隆及深拷贝和浅拷贝
使用场景: 在日常的编程过程 中,经常会遇到,有一个对象OA,在某一时间点OA中已经包含了一些有效值 ,此时可能会需一个和OA完全相对的新对象OB,并且要在后面的操作中对OB的任何改动都不会影响到OA ...
- java克隆之深拷贝与浅拷贝
版权声明:本文出自汪磊的博客,转载请务必注明出处. Java深拷贝与浅拷贝实际项目中用的不多,但是对于理解Java中值传递,引用传递十分重要,同时个人认为对于理解内存模型也有帮助,况且面试中也是经常问 ...
随机推荐
- 【动画消消乐 】HTML+CSS 吃豆豆动画 073
前言 Hello!小伙伴! 非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出- 自我介绍 ଘ(੭ˊᵕˋ)੭ 昵称:海轰 标签:程序猿|C++选手|学生 简介:因C语言结识编程,随后转入计 ...
- java顺序结构、循环结构、选择结构
java顺序结构.选择结构.循环结构 顺序结构: 语句与语句之间,框与框之间是从上到下的顺序进行的,它是由若干个依次执行的处理步骤执组成的,它是任何一个算法都不离开的一种基本算法结构. 选择结构: 1 ...
- YOLO-v4 口罩识别
YOLO-v4 口罩识别 一.YOLO-v4概念 如果想要了解和认识yolo-v4的基本概念,首先要提的就是它的基础版本yolo-v1,对于yolo来说,最经典的算是yolo-v3.如果想要了解它的由 ...
- 学习mybatis框架>从零开始学JAVA
目录 学习mybatis框架 mybatis框架的介绍 什么是mybatis框架 为什么要使用mybatis框架 mybatis的优点 Mybatis框架环境搭建 去官网下载jar包 创建一个普通的j ...
- UI_UE在线就业-笔记
UI设计 一.字体设计的应用范围 Logo设计.平面海报.包装设计.banner设计.APP引导页.UI图标.UI界面.影视设计 二.字体的分类 衬线字体和非衬线字体之分 区别在于笔画开始与结尾地方有 ...
- 干了快3年Android了,感觉自己的职业生涯已经快凉了
背景 首先我是个菜鸡,工资也低的一笔. 刚毕业时候在一家国企上班干 app 开发,干了快两年的时候,跳槽到了一家伪大厂干安全.投了不少简历都没有回音,只有这加伪大厂要我就来了.当时说好了会接触一些底层 ...
- 【LeetCode】169. 多数元素
169. 多数元素 知识点:数组:排序:消消乐:分治: 题目描述 给定一个大小为 n 的数组,找到其中的多数元素.多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素. 你可以假设数组是非空的, ...
- 解决SecureCRT中删除会话后无法重建问题
SecureCRT和SecureFX中创建一个会话(例如名为"10.0.2.47")后,如果删除这个会话,然后再创建一个同样名字的会话,就会报错,原因是SecureCRT在C盘上创 ...
- git submodule 操作
git submodule foreach git status 举一反三,对所有子库的操作,都可以使用 git submodule foreach 做前缀 foreach,可以记忆为for each ...
- Oracle11 创建表空间、创建角色及导入
针对日常工作中经常使用命令创建表空间,导入数据,特此记录下(windows环境下),记录中的testSpaceName是表空间名称,testUserName是用户名,userPwd 是用户密码. 1. ...