深复制与浅复制:
浅复制(shallow clone):
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
深复制(deep clone):
被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引在main方法中使用序列化深复制对象:用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
Object中的clone方法:
clone
protected Object clone()
throws CloneNotSupportedException
创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。这样做的目的是,对于任何对象 x,表达式:
x.clone() != x
为 true,表达式:
x.clone().getClass() == x.getClass()
也为 true,但这些并非必须要满足的要求。一般情况下:
x.clone().equals(x)
为 true,但这并非必须要满足的要求。
按照惯例,返回的对象应该通过调用 super.clone 获得。如果一个类及其所有的超类(Object 除外)都遵守此约定,则 x.clone().getClass() == x.getClass()。
按照惯例,此方法返回的对象应该独立于该对象(正被复制的对象)。要获得此独立性,在 super.clone 返回对象之前,有必要对该对象的一个或多个字段进行修改。这通常意味着要复制包含正在被复制对象的内部“深层结构”的所有可变对象,并使用对副本的引用替换对这些对象的引用。如果一个类只包含基本字段或对不变对象的引用,那么通常不需要修改 super.clone 返回的对象中的字段。
Object 类的 clone 方法执行特定的复制操作。首先,如果此对象的类不能实现接口 Cloneable,则会抛出 CloneNotSupportedException。注意,所有的数组都被视为实现接口 Cloneable。否则,此方法会创建此对象的类的一个新实例,并像通过分配那样,严格使用此对象相应字段的内容初始化该对象的所有字段;这些字段的内容没有被自我复制。所以,此方法执行的是该对象的“浅表复制”,而不“深层复制”操作。
Object 类本身不实现接口 Cloneable,所以在类为 Object 的对象上调用 clone 方法将会导致在运行时抛出异常。
Object的clone方法的说明:
在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。
继承自java.lang.Object类的clone()方法是浅复制。
Java中实现对象的克隆:
①为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。
②在派生类中覆盖基类的clone()方法,并声明为public。
③在派生类的clone()方法中,调用super.clone()。
④在派生类中实现Cloneable接口(一个标识性的接口)。
下面是一个实现深复制的例子:
创建Employer类,实现Cloneable接口:
/**
* 创建序列化对象
*/
class User implements Serializable{
private static final long serialVersionUID = 1L;
//transient关键字,不被序列化
transient String username;
String password;
public User(String username, String password){
this.username = username;
this.password = password;
}
}
创建Employee类,实现Cloneable接口,并改写clone方法,实现深复制:
class Employee implements Cloneable{
private String username;
private Employer employer;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Employer getEmployer() {
return employer;
}
public void setEmployer(Employer employer) {
this.employer = employer;
}
@Override
public Object clone() throws CloneNotSupportedException {
//克隆Employee对象并手动的进一步克隆Employee对象中包含的Employer对象
Employee employee = (Employee)super.clone();
employee.setEmployer((Employer) employee.getEmployer().clone());
return employee;
}
}
使用序列化来进行对象的深复制:
序列化即是把对象写到流里面的过程;反序列化即是把对象从流中读取出来的过程。写在流里的是对象的一个拷贝,而原来的对象仍然在JVM里面。
以下是实现过程描述:
前提是对象以及对象内部所有用到的对象都是可序列化的,否则就需要考虑把那些不可序列化的对象标记为transient,从而把它排除到复制范围之外。
然后使对象实现Serializable接口。
把对象写入到一个流里(不用依赖于文件,直接暂存在内存中即可),在从流里读取出来,便得到了一个深复制的对象。
下面是使用序列化实现深复制的例子:
创建Employer2类实现序列化接口:
class Employee2 implements Serializable{
private static final long serialVersionUID = 3969438177161438988L;
private String name;
private Employer2 employer;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Employer2 getEmployer() {
return employer;
}
public void setEmployer(Employer2 employer) {
this.employer = employer;
}
/**
* 实现深复制的方法
*/
public Object deepCopy() throws IOException, ClassNotFoundException{
//字节数组输出流,暂存到内存中
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//序列化
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
//反序列化
return ois.readObject();
}
}
在main方法中使用序列化深复制对象:
public static void main(String[] args) throws IOException, ClassNotFoundException {
Employer2 employer = new Employer2();
employer.setName("arthinking");
Employee2 employee = new Employee2();
employee.setName("Jason");
employee.setEmployer(employer);
//通过深复制创建employee2
Employee2 employee2 = (Employee2) employee.deepCopy();
employee2.getEmployer().setName("Jason");
System.out.println(employee.getEmployer().getName());
System.out.println(employee2.getEmployer().getName());
}
分享到:
相关推荐
深拷贝和浅拷贝一些例子
C#中的浅拷贝和深拷贝 C#中有两种类型变量,一种是值类型变量,一种是引用类型变量。
浅拷贝:浅拷贝是创建一个新的对象,该对象与原始对象共享内部元素的引用。换句话说,浅拷贝只复制了对象的第一层元素,而没有递归复制其内部嵌套的对象。因此,当修改原始对象的内部元素时,浅拷贝对象也会受到影响...
对Python中列表和数组的赋值 中 ,浅拷贝和深拷贝的实例讲解 浅 引⽤: 列表赋值: 1234567>>> a = [1, 2, 3] >>> b = a >>> print b [1, 2, 3] >>> a[0] = 0 >>> print b [0, 2, 3] 解释:[1, 2, 3]被视作⼀个对象...
首先我们看看浅拷贝和深拷贝的定义 浅拷贝:只复制一个对象,对象内部存在的指向其他对象数组或者引用则不复制 深拷贝:对象,对象内部的引用均复制 为了更好的理解它们的区别我们假设有一个对象A,它包含...
1、只有NS类型调用copy方法才是浅拷贝,其他的情况全是深拷贝 2、容器类调用copy或mutableCopy能出现的深拷贝的情况下,只是容器的深拷贝,而非容器内元素的深拷贝 3、无论是声明NSString还是NSMutableString类型的...
js浅拷贝与深拷贝的区别和实现方式.md
Java关于深拷贝(深复制)和浅拷贝(浅复制)比较通俗易懂的简单说明及示例代码...
那么如何切断a和b之间的关系呢,可以拷贝一份a的数据,根据拷贝的层级不同可以分为浅拷贝和深拷贝,浅拷贝就是只进行一层拷贝,深拷贝就是无限层级拷贝先来浅拷贝浅拷贝
让你对C++的深拷贝和浅拷贝进一步了解,自己制作的,特和大家分享
python 直接赋值、浅拷贝与深拷贝.ipynb
本文实例讲述了JS浅拷贝和深拷贝原理与实现方法。分享给大家供大家参考,具体如下: 浅拷贝只会拷贝一层,深层的引用类型改变还是会受到影响。 深拷贝是所有内部的属性还有值都被拷贝了一份,不管深层的引用类型怎么...
通过简短的代码和图片来说明C++中深拷贝和浅拷贝的区别和概念。
C#浅拷贝和深拷贝数据
copy的使用(深拷贝、浅拷贝),可以结合博客http://blog.csdn.net/aiyang10/article/details/49305477 理解
本文实例讲述了Python中字典的浅拷贝与深拷贝用法。分享给大家供大家参考,具体如下: 最近发现的一个很值得记录的东西就是python字典的浅拷贝问题 首先,明确一下什么是浅拷贝,什么是深拷贝: 简单的来说就是,在...
python的深拷贝与浅拷贝 引言 前两天在用python写A*算法的时候,被python的深拷贝和浅拷贝恶搞了一番,实际上还是因为没搞清楚哪些是深拷贝,哪些是浅拷贝,现特意写一篇小结,加深理解。 什么是浅拷贝 所谓浅拷贝,...
本文实例讲述了Python浅拷贝与深拷贝用法。分享给大家供大家参考。具体分析如下: >>> person=['name',['savings',100]] >>> hubby=person[:] >>> wifey=list(person) >>> [id(x) for x in person,hubby,wifey] ...
C#浅拷贝深拷贝
浅拷贝和深拷贝案例的代码