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中值传递,引用传递十分重要,同时个人认为对于理解内存模型也有帮助,况且面试中也是经常问 ...
随机推荐
- (python函数01)enumerate函数
enumerate函数 enumerate函数示例代码01运行结果01示例代码02运行结果02 enumerate(枚举,列举)是python的内置函数,enumerate的参数为可迭代对象,如字符串 ...
- MySQL执行计划【explain】详解
本文已经收录到github仓库,仓库用于分享Java相关知识总结,包括Java基础.MySQL.Springboot.mybatis.Redis.rabbitMQ等等,欢迎大家提pr和star! gi ...
- Js实现随机某个li样式增加
一.首先引入jquery cdn 二.基础样式 三.目的 为了使随机某个li背后有个旋转的图片 四.核心代码 html代码: <div class="bg3"> ...
- Thunder DLL Hijacking
简记 原理基础啥的俺也不写了 1.寻找DLL 生成恶意dll文件 拿calc测试 2.放入 3.打开
- 中高级Android大厂面试秘籍,为你保驾护航金三银四,直通大厂(上)
前言 当下,正面临着近几年来的最严重的互联网寒冬,听得最多的一句话便是:相见于江湖~.缩减HC.裁员不绝于耳,大家都是人心惶惶,年前如此,年后想必肯定又是一场更为惨烈的江湖厮杀.但博主始终相信,寒冬之 ...
- 授予mysql的其他用户数据库的使用权限
场景:不同的开发人员有不同的数据库的权限:也可适用于外包公司不同的开发权限. root用户登录数据库,命令行执行下面语句即可. grant select,delete,update,create,dr ...
- sqli-labs lesson 7-10 (文件导出,布尔盲注,延时注入)
写在前面: 首先需要更改一下数据库用户的权限用于我们之后的操作. 首先在mysql命令行中用show variables like '%secure%';查看 secure-file-priv 当前的 ...
- 51单片机—使用PWM对直流电机调速
文章目录 - 什么是PWM - PWM是怎么对直流电机进行调速的 - 通过定时器中断实现PWM调速 - 上代码 - 什么是PWM PWM(脉宽调制),是靠改变脉冲宽度来控制输出电压,通过改变周期来控制 ...
- MySQL05
SQL字段相关语句 添加字段 alter table 表名 add 字段名 数据类型 约束条件; 修改字段 alter table 表名 modify 字段 数据类型 约束条件; # modify只能 ...
- springboot配置ssl-pfx
application.yml server: port: 9443 ssl: key-store: classpath:4148017_qra.meeno.net.pfx key-store-typ ...