深拷贝与浅拷贝

浅拷贝

public class Student implements Cloneable{
Integer a;
Integer b; @Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
} String c;
Student child;
} public class Main { public static void main(String[] args) throws CloneNotSupportedException {
Student s = new Student();
Student s2 = (Student) s.clone();
System.out.println(s == s2);
System.out.println(s.child == s2.child);
}
}
/**********************************************************************/
false
true

由上述代码及运行结果我们可以看出,调用clone方法之后,确实s2是一个新的对象,内存地址已经发生了改变,但s和s2的child属性仍然指向相同的地址,这便是浅拷贝,当然8种基本数据类型是深拷贝,String则是例外。

深拷贝

public class Teacher implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
} public class Student implements Cloneable{
Integer a;
Integer b; public Student(Teacher t) {
this.t = t;
} @Override
protected Object clone() throws CloneNotSupportedException {
Student s = (Student) super.clone();
s.t = (Teacher)s.t.clone();//彻底深拷贝关键
return s;
} String c;
Teacher t;
} public class IntersectionofTwoArraysII { public static void main(String[] args) throws CloneNotSupportedException {
Teacher t = new Teacher();
Student s = new Student(t);
Student s2 = (Student) s.clone();
System.out.println(s == s2);
System.out.println(s.t == s2.t);
}
}
/**********************************************************************/
false
false

如上代码运行结果所示为深拷贝,想要实现深拷贝,就需要在重写Cloneable接口的clone()方法,并调用属性的clone()方法,因此关联类也要实现Cloneable接口,从而形成拷贝链,实现彻底深拷贝

实现彻底的深拷贝并不容易,因为它要求涉及的所有类都实现了cloneable接口,但是如StringBuffer由于其没有实现Cloneable接口,想要实现深拷贝效果,则需要做特殊处理从而实现深拷贝的效果。可以在clone方法中实现

sb=new StringBuffer(sb.toString());

Cloneable接口

Cloneable其实就是一个标记接口,只有实现这个接口后,然后在类中重写Object中的clone方法,然后通过类调用clone方法才能克隆成功,如果不实现Cloneable其实就是一个标记接口接口,调用clone方法则会抛出CloneNotSupportedException(克隆不被支持)异常。

如何判断类是否实现了cloneable接口呢?

/**
* Creates and returns a copy of this {@code Object}. The default
* implementation returns a so-called "shallow" copy: It creates a new
* instance of the same class and then copies the field values (including
* object references) from this instance to the new instance. A "deep" copy,
* in contrast, would also recursively clone nested objects. A subclass that
* needs to implement this kind of cloning should call {@code super.clone()}
* to create the new instance and then create deep copies of the nested,
* mutable objects.
*
* @return a copy of this object.
* @throws CloneNotSupportedException
* if this object's class does not implement the {@code
* Cloneable} interface.
*/
protected Object clone() throws CloneNotSupportedException {
if (!(this instanceof Cloneable)) {
throw new CloneNotSupportedException("Class doesn't implement Cloneable");
} return internalClone((Cloneable) this);
} /*
* Native helper method for cloning.
*/
private native Object internalClone(Cloneable o);

clone方法首先会判对象是否实现了Cloneable接口,若无则抛出CloneNotSupportedException, 最后会调用internalClone. intervalClone是一个native方法,一般来说native方法的执行效率高于非native方法。

参考资料

详解Java中的clone方法 -- 原型模式

深拷贝、浅拷贝与Cloneable接口的更多相关文章

  1. Java 深拷贝、浅拷贝及Cloneable接口

    Cloneable接口是一个空接口,仅用于标记对象,Cloneable接口里面是没有clone()方法,的clone()方法是Object类里面的方法!默认实现是一个Native方法 protecte ...

  2. 001 Java 深拷贝、浅拷贝及Cloneable接口

    原本写过,后来在阅读的时候,感觉自己都不是太明白了,删除后参考人家的又重新写了一份. 一:开篇 1.复制一个变量 举例是int类型. 其他其中七种原始数据类型同样适用. 原始类型:boolean,ch ...

  3. Java中的Cloneable接口与深拷贝、浅拷贝

    Cloneable接口是一个标记接口,也就是没有任何内容,定义如下: 这里分析一下这个接口的用法,clone方法是在Object种定义的,而且是protected型的,只有实现了这个接口,才可以在该类 ...

  4. java 的对象拷贝(有深浅拷贝两种方式,深拷贝实现的两种方式(逐层实现cloneable接口,序列化的方式来实现))

    Java提高篇--对象克隆(复制)(转自:http://www.cnblogs.com/Qian123/p/5710533.html#_label0)   阅读目录 为什么要克隆? 如何实现克隆 浅克 ...

  5. Java的一个高性能快速深拷贝方法。Cloneable?

    本人在设计数据库缓存层的时候,需要对数据进行深拷贝,这样用户操作的数据对象就是不共享的. 这个思路实际上和Erlang类似,就是用数据不共享解决并发问题. 1. 序列化? 原来的做法,是用序列化,我用 ...

  6. clone 深拷贝 浅拷贝

    1. 定义:知道一个对象,但不知道类,想要得到该对象相同的一个副本,在修改该对象的属性时,副本属性不修改,clone的是对象的属性 2. 意义:当一个对象里很多属性,想要得到一个相同的对象,还有set ...

  7. Java深拷贝浅拷贝

    首先,Java中常用的拷贝操作有三个,operator = .拷贝构造函数 和 clone()方法.由于Java不支持运算符重载,我们无法在自己的自定义类型中定义operator=.拷贝构造函数大家应 ...

  8. Java中的Cloneable接口理解

    Cloneable接口是一个标记接口,也就是没有任何内容,定义如下: 这里分析一下这个接口的用法,clone方法是在Object种定义的,而且是protected型的,只有实现了这个接口,才可以在该类 ...

  9. Java 深拷贝浅拷贝 与 序列化

    一.浅拷贝.深拷贝 浅拷贝会对对象中的成员变量进行拷贝:如果是基本类型,拷贝的就是基本类型的值:如果属性是内存地址(引用类型),拷贝的就是内存地址 : 深拷贝,除了基本类型外,引用类型所引用的对象也会 ...

随机推荐

  1. 透过源码分析ArrayList运作原理

    List接口的主要实现类ArrayList,是线程不安全的,执行效率高:底层基于Object[] elementData 实现,是一个动态数组,它的容量能动态增加和减少.可以通过元素下标访问对象,使用 ...

  2. STM32CubeMX工程定时器配置

    STM32CubeMX生成工程 选择自己的芯片型号 配置RCC寄存器时钟为外部晶振 单击芯片配置GPIO,选择输出方式,重命名标签等 进入时钟配置,本人使用的为8M外部晶振作为时钟源,PLL时钟源选择 ...

  3. centos 64位安装jpeg-6b

    先安装libtool和libtool-ltdl-devel 用find命令查找config.sub和config.guess文件 find / -name config.sub find / -nam ...

  4. wireshark抓包实战(一),抓包原理

    一.什么样的"包"能被wireshark抓住呢? 1.本机 即直接抓取进出本机网卡的流量包.这种情况下,wireshark会绑定本机的一块网卡. 2.集线器 用于抓取流量泛洪,冲突 ...

  5. Java第十五天,泛型

    一.定义 泛型是一种未知的数据类型,即当我们不知道该使用哪种数据类型的时候,可以使用泛型. 泛型的本质是为了  参数化 类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型) ...

  6. IDEA永久激活码获取

      废话少说,直接上地址:http://idea.medeming.com/jet/ *小编还是建议,有家底的程序猿还是直接买正版的号,非正版的很多不便的地方~

  7. defer使用小结

    defer 前言 defer的定义 defer执行的规则 为什么需要defer defer进阶 作为匿名函数 作为函数参数 defer命令执行的时机 defer配合recover 总结 参考 defe ...

  8. RESTful API设计的点

    RESTful API 前言 一直在使用RESTful API,但是好像概念还是很模糊的,总结下使用到的点 设计的规范 协议 API与用户的通信协议,总是使用HTTPs协议. 域名 应该尽量将API部 ...

  9. 智能指针 unique_ptr

    unique_ptr 不共享它的指针.它无法复制到其他 unique_ptr,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL) 算法. 1.不能进行复制构造和赋值操作(unique ...

  10. 如何使用Swagger-UI在线生成漂亮的接口文档

    一.简单介绍 Swagger是一个实现了OpenAPI(OpenAPI Specification)规范的工具集.OpenAPI是Linux基金会的一个项目,试图通过定义一种用来描述API格式或API ...