java对象的克隆

       克隆(复制)在Java中是一种常见的操作,目的是快速获取一个对象副本。 克隆分为深克隆和浅克隆。 浅克隆 :创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

1,克隆的分类

深克隆与浅克隆的区别就是,浅克隆不会克隆原对象中的引用类型,仅仅拷贝了引用类型的指向。深克隆则拷贝了所有。也就是说深克隆能够做到原对象和新对象之间完全没有影响。

下面举例说明:

1,浅克隆,基本数据类型会拷贝值,引用类型拷贝的是引用。

import java.io.Closeable;
import java.io.IOException;

public class Person implements Cloneable {

    private String name;
    private int age;
    private String address;
    private BodyParam param;

    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 String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public BodyParam getParam() {
        return param;
    }

    public void setParam(BodyParam param) {
        this.param = param;
    }

    protected Person clone() throws CloneNotSupportedException {
        Person person = (Person) super.clone();
        return person;
    }

    public String toString(){
        return "Person is [name="+name+"age="+age+"address="+address+"param"+param+"]";
    }
}
    @Test
    public void testClone() throws CloneNotSupportedException {
        Person person = new Person();
        person.setName("mjdai");
        person.setAge(18);
        person.setAddress("shenzhen");
        BodyParam bodyParam = new BodyParam();
        bodyParam.setHand("hand");
        bodyParam.setFoot("foot");
        person.setParam(bodyParam);
        System.out.println(person.toString());
        // 浅克隆 拷贝的是引用
        Person closePerson = person.clone();
        System.out.println(closePerson.toString());
    }

结果如下所示:

Connected to the target VM, address: '127.0.0.1:59782', transport: 'socket'
person is :Person is [name=mjdaiage=18address=shenzhenparamBodyParam@6536e911]
clonePerson is :Person is [name=mjdaiage=18address=shenzhenparamBodyParam@6536e911]
Disconnected from the target VM, address: '127.0.0.1:59782', transport: 'socket'

2,深克隆,深克隆需要采用流的写入写出实现:

在需要被克隆的对象中实现如下方法。

    // 深拷贝
    protected Person deepClone() throws IOException, ClassNotFoundException {

        // 将当前对象写入流中
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);

        // 将对象从流中读取出来
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (Person)ois.readObject();
    }

测试方法:

    @Test
    public void testClone() throws CloneNotSupportedException, IOException,         
    ClassNotFoundException {
        Person person = new Person();
        person.setName("mjdai");
        person.setAge(18);
        person.setAddress("shenzhen");
        BodyParam bodyParam = new BodyParam();
        bodyParam.setHand("hand");
        bodyParam.setFoot("foot");
        person.setParam(bodyParam);
        System.out.println("person is :"+person.toString());

        // 浅克隆 拷贝的是引用
        Person clonePerson = person.clone();
        System.out.println("clonePerson is :"+clonePerson.toString());

        // 浅克隆 拷贝的是引用
        Person deepClosePerson = person.deepClone();
        System.out.println("deepClosePerson is :"+deepClosePerson.toString());
    }

测试结果:

Connected to the target VM, address: '127.0.0.1:61976', transport: 'socket'
person is :Person is [name=mjdaiage=18address=shenzhenparamBodyParam@6536e911]
clonePerson is :Person is [name=mjdaiage=18address=shenzhenparamBodyParam@6536e911]
deepClosePerson is :Person is [name=mjdaiage=18address=shenzhenparamBodyParam@46daef40]
Disconnected from the target VM, address: '127.0.0.1:61976', transport: 'socket'

需要注意的是如果没有实现序列化的话,是会报错的:

测试去掉引用对象的序列化:

public class BodyParam implements Cloneable, Serializable 

去掉Serializable,测试结果如下:

Connected to the target VM, address: '127.0.0.1:51295', transport: 'socket'
person is :Person is [name=mjdaiage=18address=shenzhenparamBodyParam@6536e911]
clonePerson is :Person is [name=mjdaiage=18address=shenzhenparamBodyParam@6536e911]

java.io.NotSerializableException: BodyParam

	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
	at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
	at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
	at Person.deepClone(Person.java:54)
	at TestClone.testClone(TestClone.java:24)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

恢复public class BodyParam implements Cloneable, Serializable

去掉public class Person implements Cloneable ,Serializable中的Serializable

结果如下:

Connected to the target VM, address: '127.0.0.1:56254', transport: 'socket'
person is :Person is [name=mjdaiage=18address=shenzhenparamBodyParam@6536e911]
clonePerson is :Person is [name=mjdaiage=18address=shenzhenparamBodyParam@6536e911]

java.io.NotSerializableException: Person

	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
	at Person.deepClone(Person.java:54)
	at TestClone.testClone(TestClone.java:24)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

Disconnected from the target VM, address: '127.0.0.1:56254', transport: 'socket'

Process finished with exit code -1

如上就是java克隆的简单测试验证,当然序列化可以使用其他的方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值