zoukankan      html  css  js  c++  java
  • Java克隆--深克隆与浅克隆的区别

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

      要注意的是要克隆的对象的泪必须继承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+"
    ");
    		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+"
    ");
    		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异常

  • 相关阅读:
    字符串基本操作
    条件、循环、函数定义 练习
    turtle库基础练习
    Python基础练习
    AutoLayout 教程
    Mac上最佳的SVN管理工具:Cornerstone
    图片上传 关于压缩的问题
    关于单元测试的问题
    获取ios设备的当前IP地址
    关于项目使用ARC的管理方式
  • 原文地址:https://www.cnblogs.com/luankun0214/p/4395782.html
Copyright © 2011-2022 走看看