001 Java 深拷贝、浅拷贝及Cloneable接口
原本写过,后来在阅读的时候,感觉自己都不是太明白了,删除后参考人家的又重新写了一份。
一:开篇
1.复制一个变量
举例是int类型。
其他其中七种原始数据类型同样适用。
原始类型:boolean,char,byte,short,float,double.long
int apples = 5;
int pears = apples;
2.复制一个对象
package com.jun.it;
public class CopyTest {
public static void main(String[] args) {
Student student1=new Student();
student1.setNumber(123);
//复制
Student student2=student1;
System.out.println("学生1:"+student1.getNumber());
System.out.println("学生2:"+student2.getNumber());
}
}
class Student{
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
3.效果

4.接着说明
上面是一个简单的对象复制,但是这种复制有没有问题,下面添加一行程序:student2.setNumber(456);
效果就变了,效果如下:

完整的程序:
package com.jun.it;
public class CopyTest {
public static void main(String[] args) {
Student student1=new Student();
student1.setNumber(123);
//复制
Student student2=student1;
student2.setNumber(456);
System.out.println("学生1:"+student1.getNumber());
System.out.println("学生2:"+student2.getNumber());
}
}
class Student{
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
5.结论
在修改2的时候,1也随着改变了。
因为在内存堆中是同一个对象。
这样的复制是有问题的,所以,具体怎么样才能算一个复制对象呢?
在下面会具体的说明。
二:复制原理的说明
1.Object
在Object中,有11个方法,有两个projected的方法,其中一个为clone。
并且clone是一个native方法,说明这是一个供java调用的程序。
每个类都直接或者间接的父类都是Object,都有clone方法,但是都是projected的,所以不能进行类外进行访问。
所以,要对对象的复制,就需要对clone方法进行覆盖。
三:为什么要克隆
1.说明
在引入克隆的示例之后,需要说明为什么要克隆,直接new对象不好么
2.克隆
克隆的对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠clone方法了。
通过上面的源码都发现了clone是一个native方法,就是快啊,在底层实现的。
通过clone方法赋值的对象跟原来的对象时同时独立存在的
四:如何克隆
1.克隆的两种方式
分为浅克隆,和深克隆。
数据类型主要分为值类型和引用类型。
浅克隆与深克隆主要的区别在于是否支持引用类型的成员变量的复制。
五:浅克隆
1.步骤
被复制的类需要实现Clonenable接口
如果不实现,直接调用clone方法,会抛出CloneNotSupportedException异常
覆盖clone方法,访问修饰符设置为public。
在调用super.clone()可以得到需要的复制对象。
2.程序示例
对刚刚的对象程序,做一个修改。
package com.jun.it;
public class CopyTest2 {
public static void main(String[] args) {
Student2 student1=new Student2();
student1.setNumber(123);
//复制
Student2 student2=(Student2)student1.clone();
System.out.println("学生1:"+student1.getNumber());
System.out.println("学生2:"+student2.getNumber());
student2.setNumber(456);
System.out.println("学生1:"+student1.getNumber());
System.out.println("学生2:"+student2.getNumber());
}
}
class Student2 implements Cloneable{
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
//clone
public Object clone() {
Student2 stu=null;
try {
stu=(Student2)super.clone();
}catch (Exception e) {
e.printStackTrace();
}
return stu;
}
}
3.效果
这样的复制,已经不再是同一个对象了。

六:深度复制
1.对象中有引用一个引用类型的时候
这个深度复制,是源于上面的浅复制。
现在,在Student类中加入一个Adress类。
2.程序
在修改后的程序,观察是否可以做到合适的复制呢?
package com.jun.it;
public class CopyTest3 {
public static void main(String[] args) {
Address address=new Address();
address.setAddress("北京");
Student3 student1=new Student3();
student1.setAddress(address);
//复制
Student3 student2=(Student3)student1.clone();
System.out.println("学生1:"+student1.getAddress().getAddress());
System.out.println("学生2:"+student2.getAddress().getAddress());
address.setAddress("上海"); System.out.println("学生1:"+student1.getAddress().getAddress());
System.out.println("学生2:"+student2.getAddress().getAddress());
}
}
/**
* Address
* @author dell
*
*/
class Address{
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
/**
* Student
* @author dell
*
*/
class Student3 implements Cloneable{
private int number;
private Address address;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
//clone
public Object clone() {
Student3 stu=null;
try {
stu=(Student3)super.clone();
}catch (Exception e) {
e.printStackTrace();
}
return stu;
}
}
3.效果
在修改地址后,发现不是合适的复制。

4.结论
原因在浅复制,只是复制了address变量的引用,没有正真的开辟一个新的空间,将复制后再把引用返回给新的对象。
所以,需要正真的复制对象,而不是纯粹的引用复制。
可以让Address类可以被复制化,并且修改clone方法。
5.最新的程序
package com.jun.it;
public class CopyTest3 {
public static void main(String[] args) {
Address address=new Address();
address.setAddress("北京");
Student3 student1=new Student3();
student1.setAddress(address);
//复制
Student3 student2=(Student3)student1.clone();
System.out.println("学生1:"+student1.getAddress().getAddress());
System.out.println("学生2:"+student2.getAddress().getAddress());
address.setAddress("上海");
System.out.println("学生1:"+student1.getAddress().getAddress());
System.out.println("学生2:"+student2.getAddress().getAddress());
}
}
/**
* Address
* @author dell
*
*/
class Address implements Cloneable{
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
//clone
public Object clone() {
Address address=null;
try {
address=(Address)super.clone();
}catch (Exception e) {
e.printStackTrace();
}
return address;
}
}
/**
* Student
* @author dell
*
*/
class Student3 implements Cloneable{
private int number;
private Address address;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
//clone
public Object clone() {
Student3 stu=null;
try {
//浅复制
stu=(Student3)super.clone();
}catch (Exception e) {
e.printStackTrace();
}
//深复制
stu.address=(Address)address.clone();
return stu;
}
}
6.效果

001 Java 深拷贝、浅拷贝及Cloneable接口的更多相关文章
- Java 深拷贝、浅拷贝及Cloneable接口
Cloneable接口是一个空接口,仅用于标记对象,Cloneable接口里面是没有clone()方法,的clone()方法是Object类里面的方法!默认实现是一个Native方法 protecte ...
- 深拷贝、浅拷贝与Cloneable接口
深拷贝与浅拷贝 浅拷贝 public class Student implements Cloneable{ Integer a; Integer b; @Override protected Obj ...
- Java深拷贝浅拷贝
首先,Java中常用的拷贝操作有三个,operator = .拷贝构造函数 和 clone()方法.由于Java不支持运算符重载,我们无法在自己的自定义类型中定义operator=.拷贝构造函数大家应 ...
- Java 深拷贝浅拷贝 与 序列化
一.浅拷贝.深拷贝 浅拷贝会对对象中的成员变量进行拷贝:如果是基本类型,拷贝的就是基本类型的值:如果属性是内存地址(引用类型),拷贝的就是内存地址 : 深拷贝,除了基本类型外,引用类型所引用的对象也会 ...
- java 的对象拷贝(有深浅拷贝两种方式,深拷贝实现的两种方式(逐层实现cloneable接口,序列化的方式来实现))
Java提高篇--对象克隆(复制)(转自:http://www.cnblogs.com/Qian123/p/5710533.html#_label0) 阅读目录 为什么要克隆? 如何实现克隆 浅克 ...
- Java clone() 浅拷贝 深拷贝
假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short, ...
- 一步步分析Java深拷贝的两种方式-clone和序列化
今天遇到一道面试题,询问深拷贝的两种方法.主要就是clone方法和序列化方法.今天就来分析一下这两种方式如何实现深拷贝.如果想跳过解析的朋友,直奔"重点来了!"寻找答案. clon ...
- Cloneable接口和Object的clone()方法
为什么要克隆 为什么要使用克隆,这其实反映的是一个很现实的问题,假如我们有一个对象: public class SimpleObject implements Cloneable { private ...
- Java中的Cloneable接口与深拷贝、浅拷贝
Cloneable接口是一个标记接口,也就是没有任何内容,定义如下: 这里分析一下这个接口的用法,clone方法是在Object种定义的,而且是protected型的,只有实现了这个接口,才可以在该类 ...
随机推荐
- Mongodb 笔记03 查询、索引
查询 1. MongoDB使用find来进行查询.find的第一个参数决定了要返回哪些文档,这个参数是一个文档,用于指定查询条件.空的查询会匹配集合的全部内容.要是不指定查询,默认是{}. 2. 可以 ...
- javascript精雕细琢(三):作用域与作用域链
目录 引言 1.执行环境 2.作用域与作用域链 引言 作用域与作用域链是JS应用中无时无刻不在影响程序运行的关键属性,但是由于它的不可见性,或者说它存在的过于普遍,简直就像空气一样.所以 ...
- [2009国家集训队]小Z的袜子(hose) 浅谈莫队
浅谈莫队 推荐学习博客 http://foreseeable97.logdown.com/posts/158522-233333 借用题目: bzoj 2038 2009 国家集训队 小Z的袜子htt ...
- Java并发编程原理与实战二十二:Condition的使用
Condition的使用 Condition用于实现条件锁,可以唤醒指定的阻塞线程.下面来实现一个多线程顺序打印a,b,c的例子. 先来看用wait和notify的实现: public class D ...
- Jupyter Notebook Tutorial: Introduction, Setup, and Walkthrough
Jupyter Notebook Tutorial: Introduction, Setup, and Walkthrough YouTube https://www.youtube.com/watc ...
- anonymous namespace V.S. static variant
[anonymous namespace V.S. static variant] 在C语言中,如果我们在多个tu(translation unit)中使用了同一个名字做为函数名或者全局变量名,则在链 ...
- 微服务深入浅出(3)-- 服务的注册和发现Eureka
现来说一些Eureka的概念: 1.服务注册 Register 就是Client向Server注册的时候提供自身元数据,比如IP和Port等信息. 2.服务续约 Renew Client默认每隔30s ...
- Pythagorean Triples(Codeforces Round #368 (Div. 2) + 构建直角三角形)
题目链接: https://codeforces.com/contest/707/problem/C 题目: 题意: 告诉你直角三角形的一条边,要你输出另外两条边. 思路: 我们容易发现除2外的所有素 ...
- Linux基础-软硬连接Block概念
建立/etc/passwd的软连接文件,放在/tmp目录下 使用文件名方式建立的软连接可以跨分区,删除目标文件后,软连接文件失效 建立/etc/passwd的硬链接文件,放在/boot下,如果不成功, ...
- A - ACM Computer Factory(网络流)
题目链接:https://cn.vjudge.net/contest/68128#problem/A 反思:注意拆点,否则的话节点就没用了,还有注意源点和汇点的赋值. AC代码: #include&l ...