基本数据类型引用数据类型特点

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() 方法克隆对象——深拷贝与浅拷贝的更多相关文章

  1. Java 中如何使用clone()方法克隆对象?

    java为什么要 对象克隆: 在程序开发时,有时可能会遇到以下情况:已经存在一个对象A,现在需要一个与A对象完全相同的B 对象,并对B 对象的属性值进行修改,但是A 对象原有的属性值不能改变.这时,如 ...

  2. java对象的克隆以及深拷贝与浅拷贝

    一.为什么要使用克隆 在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能 会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也 ...

  3. 关于Java的Object.clone()方法与对象的深浅拷贝

    文章同步更新在个人博客:关于Java的Object.clone()方法与对象的深浅拷贝 引言 在某些场景中,我们需要获取到一个对象的拷贝用于某些处理.这时候就可以用到Java中的Object.clon ...

  4. Object.clone()方法与对象的深浅拷贝

    转载:[https://www.cnblogs.com/nickhan/p/8569329.html] 引言 在某些场景中,我们需要获取到一个对象的拷贝用于某些处理.这时候就可以用到Java中的Obj ...

  5. javascript对象深拷贝,浅拷贝 ,支持数组

    javascript对象深拷贝,浅拷贝 ,支持数组 经常看到讨论c#深拷贝,浅拷贝的博客,最近js写的比较多, 所以也来玩玩js的对象拷贝. 下面是维基百科对深浅拷贝的解释: 浅拷贝 One meth ...

  6. Java clone方法(下)

    1.终于调用的是一个JNI方法,即java本地方法,加高速度 2.使用clone方法,分为浅复制.深复制,这里直接使用网上抄来的案例来说明吧: 说明: 1)为什么我们在派生类中覆盖Object的clo ...

  7. java对象克隆以及深拷贝和浅拷贝

    1.什么是"克隆"? 在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能 会需要一个和A完全相同新对象B,并且此后对B任何改动都不 ...

  8. JAVA中对象的克隆及深拷贝和浅拷贝

    使用场景: 在日常的编程过程 中,经常会遇到,有一个对象OA,在某一时间点OA中已经包含了一些有效值 ,此时可能会需一个和OA完全相对的新对象OB,并且要在后面的操作中对OB的任何改动都不会影响到OA ...

  9. java克隆之深拷贝与浅拷贝

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java深拷贝与浅拷贝实际项目中用的不多,但是对于理解Java中值传递,引用传递十分重要,同时个人认为对于理解内存模型也有帮助,况且面试中也是经常问 ...

随机推荐

  1. 🔥 LeetCode 热题 HOT 100(71-80)

    253. 会议室 II(NO) 279. 完全平方数 class Solution { public int numSquares(int n) { // dp[i] : 组成和为 i 的最少完全平方 ...

  2. 2019.06.28 MERGE INTO备忘

    --保存主表 MERGE INTO dbo.DeliveryReceiving AS t USING @ReceiveMainDt AS s ON t.Id=s.id WHEN MATCHED THE ...

  3. 利用MySQL原数据信息批量转换指定库数据表生成Hive建表语句

    1.写出文件工具类 package ccc.utile; import java.io.*; /** * @author ccc * @version 1.0.0 * @ClassName Write ...

  4. Java数组02——三种初始化及内存分析

    内存分析 三种初始化 例子  package array; ​ public class ArrayDemon02 {     public static void main(String[] arg ...

  5. 阿里三面Android开发岗都过了,但是无理由挂了,竟是HR骚操作?

    进入互联网大厂一般都是"过五关斩六将",难度堪比西天取经,但当你真正面对这些大厂的面试时,有时候又会被其中的神操作弄的很是蒙圈. 近日,某位程序员发帖称,自己去阿里面试Androi ...

  6. .Net Core+分布式配置中心(AgileConfig)

    GitHub上AgileConfig非常详细,以下只是本人学习过程的整理 一.介绍 1.参考地址 https://github.com/dotnetcore/AgileConfig https://w ...

  7. bat脚本中%~dp0含义解释

    在Windows脚本中,%i类似于shell脚本中的$i,%0表示脚本本身,%1表示脚本的第一个参数,以此类推到%9,在%和i之间可以有"修饰符"(完整列表可通过"for ...

  8. LoadableComponent类的使用

    通过继承LoadableComponent类,测试程序可以判断浏览器是否加载了正确的页面,只需要重写isLoaded和load二个方法,此方法有助于页面对象的页面访问操作更加稳定 1.LoginPag ...

  9. 浅谈 SQL 注入(注入篇)

    一.SQL注入简介 1.1 什么是SQL注入 在用户可控制的参数上过滤不严或没有任何限制,使得用户将传入的参数(如URL,表单,http header)与SQL语句合并构成一条 SQL语句传递给web ...

  10. Docker++:从 0 到 1 学习Docker(笔记)

    本篇文章有点长 ... 知识点如下:下 ↓ ↓ ↓ ~ 初识 Docker  ~ Docker 命令 ~ Docker 容器的数据卷 ~ Docker 应用部署 ~ Dockerfile ~ Dock ...