java中cloneable的使用

来源:互联网 发布:开源股票软件 python 编辑:程序博客网 时间:2024/05/17 07:20
什么是java中的浅克隆和深克隆?
  • 浅克隆:克隆对象中的变量与之前对象的值相同,并且对象中的引用类型变量仍然指向原来对象引用类型变量的地址.
  • 深克隆:克隆对象中的变量与之前对象的值相同,并且对象中的引用类型变量指向了新的对象的引用变量的地址.
  • 要想实现克隆,只需定义的类声明下cloneable这个标记性接口,并且衍生重写Object类中就有的clone()方法即可.

为什么类要首先声明cloneable标记接口,然后重写clone()方法?因为不声明cloneable调用clone()方法会抛出CloneNotSupportedException异常,源码如下:

protected Object clone() throws CloneNotSupportedException {        if (!(this instanceof Cloneable)) {            throw new CloneNotSupportedException("Class " + getClass().getName() +                                                 " doesn't implement Cloneable");        }        return internalClone();    }    /*     * Native helper method for cloning.     */    private native Object internalClone();

在上一节中讲了java中Serializable与Parcelable的使用序列化与反序列化的问题。事实上利用对象输出流对对象进行序列化,利用对象的输入流对对象进行反序列化也可以实现克隆,如果对象中依赖的其他对象的引用也实现了序列化(即引用类实现了serializable标记接口)就实现了深度克隆,否则实现了浅克隆.

实现了Serializable接口的Company

public class Company implements Serializable {//Serializable接口是空的,没有声明的方法及常量    private static final long serialVersionUID = 1L; //序列化标识    private String name;    private String address;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getAddress() {        return address;    }    public void setAddress(String address) {        this.address = address;    }    public Company(String name, String address) {        this.name = name;        this.address = address;    }    @Override    public String toString() {        return "company name is:"+name+",address is:"+address;    }}

获得实现了Serializable接口的克隆实例调用方法。

private <T> T getCopyObj(T t) {        ByteArrayOutputStream byteArrayOutputStream = null;        ObjectOutputStream objectOutputStream = null;        ByteArrayInputStream byteArrayInputStream = null;        ObjectInputStream objectInputStream = null;        try {            byteArrayOutputStream = new ByteArrayOutputStream();            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);            objectOutputStream.writeObject(t);//序列化对象            objectOutputStream.flush();            byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());            objectInputStream = new ObjectInputStream(byteArrayInputStream);            T t1 = (T) objectInputStream.readObject();            return t1;        } catch (Exception e) {            e.printStackTrace();        } finally {            if (byteArrayOutputStream != null) {                try {                    byteArrayOutputStream.close();                    byteArrayOutputStream = null;                } catch (IOException e) {                    e.printStackTrace();                }            }            if (objectOutputStream != null) {                try {                    objectOutputStream.close();                    objectOutputStream = null;                } catch (IOException e) {                    e.printStackTrace();                }            }            if (byteArrayInputStream != null) {                try {                    byteArrayInputStream.close();                    byteArrayInputStream = null;                } catch (IOException e) {                    e.printStackTrace();                }            }            if (objectInputStream != null) {                try {                    objectInputStream.close();                    objectInputStream = null;                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return null;    }}

测试通过的testCase,说明通过Serializable的反序列化创建的是一个新的对象,不再是之前的对象了。

    @Test    public void test() throws CloneNotSupportedException {        Company company=new Company("百度","上地十街");        Company copyCompany=getCopyObj(company);        copyCompany.setName("腾讯");        Assert.assertEquals(false,company==copyCompany);        Assert.assertEquals(true,company.getName().equals("百度"));        Assert.assertEquals(true,copyCompany.getName().equals("腾讯"));    }

实现了Clonable克隆的例子
public class People implements Cloneable {    private String name;    private int age;    public People(String name, int age) {        this.name = name;        this.age = age;    }    @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }    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;    }}

验证通过的case,表明了克隆出来的对象与原来的对象地址不一样,是一个新的对象,所以克隆对象中的name和age是新的.

    @Test    public void test() throws CloneNotSupportedException {        People people = new People("storm", 30);        People clonePeople = (People) people.clone();        clonePeople.setName("stormClone");        clonePeople.setAge(29);        Assert.assertFalse(people == clonePeople);        System.out.println("people name=" + people.getName());//people name=storm        System.out.println("people age=" + people.getAge());//people age=30        System.out.println("clonePeople name=" + clonePeople.getName());//clonePeople name=stormClone        System.out.println("clonePeople age=" + clonePeople.getAge());//clonePeople age=29    }

使用cloneable实现浅克隆

public class Animal {    private String animalName;    public Animal(String animalName) {        this.animalName = animalName;    }    public String getAnimalName() {        return animalName;    }    public void setAnimalName(String animalName) {        this.animalName = animalName;    }}
public class People implements Cloneable {    private String name;    private int age;    private Animal animal;//克隆对象中的引用型变量    public People(String name, int age,Animal animal) {        this.name = name;        this.age = age;        this.animal=animal;    }    @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }    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 Animal getAnimal() {        return animal;    }    public void setAnimal(Animal animal) {        this.animal = animal;    }}

验证通过的case,表明了克隆对象的引用型变量animal并未发生改变,也即使内存中的地址并未发生改变,所以对其name的更改会影响原对象与克隆对象的值.

    @Test    public void test() throws CloneNotSupportedException {        Animal animal=new Animal("cat");        People people = new People("storm", 30,animal);        People clonePeople = (People) people.clone();        animal.setAnimalName("dog");        Assert.assertFalse(people == clonePeople);        Assert.assertTrue(people.getAnimal()==clonePeople.getAnimal());        Assert.assertTrue(people.getAnimal().getAnimalName().equals("dog"));        Assert.assertTrue(clonePeople.getAnimal().getAnimalName().equals("dog")); }

使用cloneable实现深克隆(实现很简单只需要引用类型变量实现cloneable接口即可),相比浅克隆,只需做如下修改.

public class Animal implements Cloneable{    private String animalName;    public Animal(String animalName) {        this.animalName = animalName;    }    public String getAnimalName() {        return animalName;    }    public void setAnimalName(String animalName) {        this.animalName = animalName;    }    @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }}

验证通过的case,表明了克隆对象的引用型变量animal发生改变,也即内存中的地址发生改变,所以对其name的更改不会影响克隆对象的值.同时说明了进行深克隆会把所有的引用类型都实现cloneable接口,如果克隆对象中的引用类型变量比较多的话,这牵涉的工作量就会比较大了,这时我们考虑使用上面实现Serializable实现克隆的方式,缺点是反复进行IO操作,内存开销大.

@Test    public void test() throws CloneNotSupportedException {        Animal animal=new Animal("cat");        People people = new People("storm", 30,animal);        People clonePeople = (People) people.clone();        Animal cloneAnimal=(Animal) animal.clone();        clonePeople.setAnimal(cloneAnimal);        animal.setAnimalName("dog");        Assert.assertFalse(people == clonePeople);        Assert.assertFalse(people.getAnimal()==clonePeople.getAnimal());        Assert.assertTrue(people.getAnimal().getAnimalName().equals("dog"));        Assert.assertTrue(clonePeople.getAnimal().getAnimalName().equals("cat"));    }
原创粉丝点击