Java Clone

java clone,要想本类可以被clone,则必须实现Cloneable接口,否则会java.lang.CloneNotSupportedException。

super.clone()调用的是object的clone()。是属于浅克隆,如果属性中有对象类型的,克隆对象将会受原型对象影响,这是我们都不愿看到的事情,我们希望克隆对象像是new出来的对象一样独立。

package com.wangbiao.second;

public class TestClone {

    public static void test_first(){
        Person father=new Person("张三");
        Person son_one=new Person("大儿子");
        son_one.setFather(father);
        Person son_two=(Person) son_one.clone();
        son_two.setName("小儿子");
        
        System.out.println(son_one.getName()+"的父亲是"+son_one.getFather().getName());
        System.out.println(son_two.getName()+"的父亲是"+son_two.getFather().getName());
    }
    
    public static void test_second(){
        Person father=new Person("张三");
        Person son_one=new Person("大儿子");
        son_one.setFather(father);
        Person son_two=(Person) son_one.clone();
        System.out.println(son_one==son_two);//false说明,是在内存中新开辟了空间,克隆对象和原型对象不是指向同一内存地址。
        son_two.setName("小儿子");
        System.out.println(son_one.getFather()==son_two.getFather());//true,说明克隆对象和原型对象中的Father属性指向同一个内存地址.
        
        //现在大儿子要认一个干爹
        
        //
        son_one.getFather().setName("李四");
        
        
        System.out.println(son_one.getName()+"的父亲是"+son_one.getFather().getName());
        System.out.println(son_two.getName()+"的父亲是"+son_two.getFather().getName());
    }
    
    public static void main(String[] args) {
        //test_first();
        test_second();
    }
}


//实现了Cloneable代表该类具有被拷贝的能力。
class Person implements Cloneable {

    public Person() {
        
    }
    public Person(String name) {
        this.name=name;
    }
    
    private String name;
    private Person father;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Person getFather() {
        return father;
    }

    public void setFather(Person father) {
        this.father = father;
    }

    @Override
    protected Object clone(){
        Person p=null;
        
        //浅拷贝
        try {
            p=(Person) super.clone();
        } catch (CloneNotSupportedException e) {
           e.printStackTrace();
         }
        
        //深拷贝
//        try {
//          p=(Person) super.clone();
//            p.setFather(new Person(p.getFather().getName()));
//        } catch (CloneNotSupportedException e) {
//            e.printStackTrace();
//        }
        
        return p;
    }
}
运行的结果是:

false
true
大儿子的父亲是李四
小儿子的父亲是李四

原理就是如果类中有对象类型的属性,在克隆之后,克隆对象和原型对象中的对象类型属性将指向同一个内存空间,只有通过深克隆,才可以避免克隆对象受原型对象的影响。


还有一种方法进行深克隆,基本原理就是将被克隆的对象读入内存中,然后再读出赋给克隆对象。

package com.wangbiao.second;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Test_Clone {

	
	public static <T extends Serializable>T clone(T object) throws Exception{
		T cloneObject=null;
		
		//将对象写入字节流
		ByteArrayOutputStream byteOut=new ByteArrayOutputStream();
		ObjectOutputStream objectOut=new ObjectOutputStream(byteOut);
		objectOut.writeObject(object);
		objectOut.close();
		
		//从字节流中读出对象
		ByteArrayInputStream byteIn=new ByteArrayInputStream(byteOut.toByteArray());
		ObjectInputStream objectIn=new ObjectInputStream(byteIn);
		cloneObject=(T) objectIn.readObject();
		byteIn.close();
		
		return cloneObject;
		
	}
	
	public static void main(String[] args) throws Exception {
		Person per=new Person("大儿子");
		per.setFather(new Person("张三"));
		Person clone_per=clone(per);
		clone_per.setName("小儿子");
		
		per.getFather().setName("李四");
		System.out.println(per.getName()+"---"+per.getFather().getName());
		System.out.println(clone_per.getName()+"---"+clone_per.getFather().getName());
		
//		大儿子---李四
//		小儿子---张三
		
	}
}


class Person implements Serializable{

	public Person() {
		
	}
	public Person(String name) {
		this.name=name;
	}
	
	private String name;
	private Person father;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Person getFather() {
		return father;
	}

	public void setFather(Person father) {
		this.father = father;
	}
}


你可能感兴趣的:(java,clone)