克隆,就是复制一个对象的副本,而克隆又分浅克隆和深克隆。浅克隆是指克隆得到的对象基本类型的值改变了,而源对象的值不会变。但如果被克隆对象引用类型的值改变了,那么源对象的值同样会改变,因为引用类型在栈内存中存放的是一个引用地址,被克隆对象后也和源对象的引用地址一样,都是指向同样的内存空间的值。所以在克隆时,任何一个对象的值的改变都会令另外的值改变,所以这种情况下要用深克隆。

要注意的是要克隆的对象的泪必须继承cloneable接口。浅克隆的特点是只克隆该对象本体,它的优缺点就是一改皆改;深克隆的特点是新建对象,与源对象互不干扰,而它的优缺点也是互不干扰和麻烦。通常情况下我们使用克隆的时候都只使用浅克隆。

对克隆可以简单的理解为:当克隆一个对象时,把属性的值和方法都一起拷贝的是浅拷贝,而方法的值可以设置不同的是深克隆。深克隆要进行反序例化,先把内容输出到内存,再从内存读取。

浅克隆:

package com.lk.B;

public class Address {
private String state;
private String province;
private String city;
public Address(String state,String province,String city){
this.state = state;
this.province = province;
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
// TODO Auto-generated method stub
StringBuffer sb = new StringBuffer();
sb.append("国家:"+this.state+",");
sb.append("省:"+this.province+",");
sb.append("市:"+this.city);
return sb.toString();
}
}

  

package com.lk.B;

public class Employees implements Cloneable{
private String name;
private int age;
private Address address;
public Employees(String name,int age,Address address){
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
// TODO Auto-generated method stub
StringBuffer sb = new StringBuffer();
sb.append("姓名:"+name+",");
sb.append("年龄:"+age+"\n");
sb.append("地址"+address);
return sb.toString();
}
@Override
protected Employees clone() {//原本返回值应该是Object,但是这里返回的是Employees,为协变类型
//即子类覆盖(即重写)基类方法时,返回的类型可以是基类方法返回类型的子类。
// TODO Auto-generated method stub
Employees employee = null; try {
employee = (Employees) super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return employee;
}
}

  

package com.lk.B;

public class Test2 {

	public static void main(String[] args) {//此方法并没有克隆成功,原因是对于引用类型不能使用浅克隆
// TODO Auto-generated method stub
System.out.println("克隆之前:");
Address address = new Address("中国", "黑龙江", "哈尔滨");
Employees employee1 = new Employees("阿坤", 21, address);
System.out.println("员工1的信息:");
System.out.println(employee1);
System.out.println("克隆之后:");
Employees employee2 = employee1.clone();
employee2.getAddress().setState("中国");
employee2.getAddress().setProvince("上海");
employee2.getAddress().setCity("杨浦");
employee2.setName("lk");
employee2.setAge(22);
System.out.println("员工2的信息:");
System.out.println(employee2);
System.out.println("员工1的信息:");
System.out.println(employee1);
} }

  输出:

/*
克隆之前:
员工1的信息:
姓名:阿坤,年龄:21
地址国家:中国,省:黑龙江,市:哈尔滨
克隆之后:
员工2的信息:
姓名:lk,年龄:22
地址国家:杨浦,省:上海,市:哈尔滨
员工1的信息:
姓名:阿坤,年龄:21
地址国家:杨浦,省:上海,市:杨浦
*/

  

此时并没有克隆成功,因为对于引用类型不能使用浅克隆,需要使用深克隆

实现深克隆有两种方法,这里先介绍第一种方法:一次克隆各个可变的引用类型:即只要有类中包含了引用类型就将那个引用类型进行克隆,在这个例子里,即需要对Address类也需要克隆,由于Address中都是基本类型(String在这里我先叫做基本类型,因为String比较特殊)

深克隆:

package com.lk.B;

public class Address implements Cloneable{
private String state;
private String province;
private String city;
public Address(String state,String province,String city){
this.state = state;
this.province = province;
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
// TODO Auto-generated method stub
StringBuffer sb = new StringBuffer();
sb.append("国家:"+this.state+",");
sb.append("省:"+this.province+",");
sb.append("市:"+this.city);
return sb.toString();
}
@Override
protected Address clone() {
// TODO Auto-generated method stub
Address address = null;
try {
address = (Address) super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return address;
}
}

  

package com.lk.B;

public class Employees implements Cloneable{
private String name;
private int age;
private Address address;
public Employees(String name,int age,Address address){
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
// TODO Auto-generated method stub
StringBuffer sb = new StringBuffer();
sb.append("姓名:"+name+",");
sb.append("年龄:"+age+"\n");
sb.append("地址"+address);
return sb.toString();
}
@Override
protected Employees clone() {//原本返回值应该是Object,但是这里返回的是Employees,为协变类型
//即子类覆盖(即重写)基类方法时,返回的类型可以是基类方法返回类型的子类。
// TODO Auto-generated method stub
Employees employee = null; try {
employee = (Employees) super.clone();
employee.address = address.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return employee;
}
}

  

package com.lk.B;

public class Test2 {

	public static void main(String[] args) {//深克隆,克隆成功
// TODO Auto-generated method stub
System.out.println("克隆之前:");
Address address = new Address("中国", "黑龙江", "哈尔滨");
Employees employee1 = new Employees("阿坤", 21, address);
System.out.println("员工1的信息:");
System.out.println(employee1);
System.out.println("克隆之后:");
Employees employee2 = employee1.clone();
employee2.getAddress().setState("中国");
employee2.getAddress().setProvince("上海");
employee2.getAddress().setCity("杨浦");
employee2.setName("lk");
employee2.setAge(22);
System.out.println("员工2的信息:");
System.out.println(employee2);
System.out.println("员工1的信息:");
System.out.println(employee1);
} }

  

/*
克隆之前:
员工1的信息:
姓名:阿坤,年龄:21
地址国家:中国,省:黑龙江,市:哈尔滨
克隆之后:
员工2的信息:
姓名:lk,年龄:22
地址国家:中国,省:上海,市:杨浦
员工1的信息:
姓名:阿坤,年龄:21
地址国家:中国,省:黑龙江,市:哈尔滨 */

  注意:使用重写clone方法时必须要实现Cloneable接口,否则会出现:java.lang.CloneNotSupportedException异常

Java克隆--深克隆与浅克隆的区别的更多相关文章

  1. 浅谈Java中的深克隆和浅克隆(阿里面试)

    在最近的秋招中,阿里和多益网络都问到了这个问题,虽然很简单,但是我还是想总结一下,感兴趣的可以看一下我的个人博客网站(Spring+MyBatis+redis+nginx+mysql)(适合菜鸟),最 ...

  2. java克隆机制

    看了下面博客就很明白了 http://www.cnblogs.com/Qian123/p/5710533.html#_label0 java对象创建方式有三种: 1.通过new对象 2.通过java克 ...

  3. JavaScript的深克隆与浅克隆

    JS数据类型分为两类: 基本类型(Number.Boolean.Undefined.Null.String.Symbol(ES6新加,此处不讨论))与引用类型(Object).原始类型存储的是对象的实 ...

  4. Java中Set Map List 的区别

    java中set map list的区别: 都是集合接口 简要说明 set --其中的值不允许重复,无序的数据结构 list   --其中的值允许重复,因为其为有序的数据结构 map--成对的数据结构 ...

  5. Java中Comparable和Comparator接口区别分析

    Java中Comparable和Comparator接口区别分析 来源:码农网 | 时间:2015-03-16 10:25:20 | 阅读数:8902 [导读] 本文要来详细分析一下Java中Comp ...

  6. 转:Java中abstract和interface的区别

    转自:Java中abstract和interface的区别 abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java ...

  7. Java abstract class 和 interface 的区别

    Java abstract class 和 interface 的区别 1. abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制 2. 以Door的抽象概 ...

  8. java虚拟机和Dalvik虚拟机的区别

    java虚拟机和Dalvik虚拟机的区别: java虚拟机Dalvik虚拟机 java虚拟机基于栈. 基于栈的机器必须使用指令来载入和操作栈上数据,所需指令更多更多dalvik虚拟机是基于寄存器的 j ...

  9. Java中this与super的区别【6】

    若有不正之处,请多多谅解并欢迎批评指正,不甚感激.请尊重作者劳动成果: 本文原创作者:pipi-changing本文原创出处:http://www.cnblogs.com/pipi-changing/ ...

随机推荐

  1. css3妙用 刷新图标

    从猫眼电影看到的一个图标 .geopos i:before { content: ""; width: .8em; height: .8em; border: .14em soli ...

  2. JavaServer Faces 2.2 requires Dynamic Web Module 2.5 or newer

    Description Resource Path Location Type JavaServer Faces 2.2 can not be installed : One or more cons ...

  3. BeanFactory和ApplicationContext的作用和区别

    BeanFactory和ApplicationContext的作用和区别 作用: 1. BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责be ...

  4. 消息系统Kafka介绍 - 董的博客

    1.  概述 Kafka是Linkedin于2010年12月份开源的消息系统,它主要用于处理活跃的流式数据.活跃的流式数据在web网站应用中非常常见,这些数据包括网站的pv.用户访问了什么内容,搜索了 ...

  5. EasyUI ComboBox默认值

    combobox数据加载完后设置默认值 $('#ck').combobox({ url: '/External/GetAllCk', valueField: 'Ddbh', textField: 'D ...

  6. C++ 中 int,char*,string,CString之间相互转换-整理

    <多字符集下> #include <string> //使用C++标准库的string类时, 定义时 std::string str; using namespace std; ...

  7. SAE J1850 VPW PWM, SAE J2411 SWC, ISO 11898 CAN, SAE J1708, Chrysler CCD 接口芯片电路

    SAE J1850 VPW 接口芯片电路 SAE J1850 PWM 接口芯片电路 SAE J2411 SWC 接口芯片电路 ISO 11898 CAN 接口芯片电路 CANH 和CANL 上的电容 ...

  8. SQL扫描并执行文件夹里的sql脚本

    场景:项目数据库操作全部使用存储过程实现.每天都会有很多存储过程更新/增加,人工对测试环境中存储过程更新,会有一定概率出现遗漏,也麻烦!所以,需要一个工具将文件夹中所有存         储过程执行一 ...

  9. 【转】selenium及webdriver的原理

    主要内容转自:http://blog.csdn.net/ant_ren/article/details/7968582和http://blog.csdn.net/ant_ren/article/det ...

  10. Codeforces Round #311 (Div. 2) E. Ann and Half-Palindrome 字典树/半回文串

    E. Ann and Half-Palindrome Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contes ...