Java对象克隆

来源:互联网 发布:解压缩软件下载免费版 编辑:程序博客网 时间:2024/06/09 15:13

Java对象克隆

1. 介绍

克隆就是复制一个对象的副本。Java支持我们对一个对象进行克隆,通常用在装饰模式和原型模式中。

一个对象中可能有基本数据类型(如:int、long、double等)的属性,也同时含有引用数据类型(如数组、集合等)的属性,所以在对象克隆时分为浅克隆与深克隆两种。那么,什么是浅克隆,什么又是深克隆呢?

浅克隆是指克隆对象时仅仅克隆对象本身(包括对象中的基本类型的变量),而不克隆对象包含的引用指向的子对象,即克隆对象与被克隆对象共享子对象。

深克隆不仅克隆对象本身,而且克隆对象包含的引用指向的所有子对象。

2. clone()方法

Object类中的clone()方法可以实现将对象复制一份并返回给调用者。一般而言,clone()方法满足:

  1. 对任何的对象obj,都有obj.clone() != obj,即克隆对象与原对象不是同一个对象。
  2. 对任何的对象obj,都有obj.clone().getClass() == obj.getClass(),即克隆对象与原对象的类型一样。
  3. 如果对象obj的equals()方法定义恰当,那么obj.clone().equals(obj)应该成立。

Object类的clone()方法执行特定的复制操作,如果此对象的类不能实现接口Cloneable,则会抛出CloneNotSupportedException异常。

在Java中,为了获取对象的一份拷贝,我们可以重写Object类的clone()方法,一般遵循下列步骤:

  1. 在类中实现Cloneable接口。
  2. 在类中覆盖基类的clone()方法,并声明为public。
  3. 在派生类的clone()方法中,调用super.clone()

3. 浅克隆

示例:

地址类:

package test.clone;/** * 地址类 *  * @author 小明 * */public class Address implements Cloneable {    private String province; // 省    private String city; // 市    private String detail; // 详细地址    public Address() {        super();    }    public Address(String province, String city, String detail) {        super();        this.province = province;        this.city = city;        this.detail = detail;    }    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;    }    public String getDetail() {        return detail;    }    public void setDetail(String detail) {        this.detail = detail;    }    @Override    public String toString() {        return "Address [province=" + province + ", city=" + city + ", detail="                + detail + "]";    }    @Override    public Object clone() throws CloneNotSupportedException {        return super.clone();    }}

学生类:

package test.clone;/** * 学生类 *  * @author 小明 * */public class Student implements Cloneable {    private String name; // 姓名    private int age; // 年龄    private Address address; // 地址    public Student() {        super();    }    public Student(String name, int age, Address address) {        super();        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() {        return "Student [name=" + name + ", age=" + age + ", address="                + address + "]";    }    @Override    public Object clone() throws CloneNotSupportedException {        return super.clone();    }}

测试类:

package test.clone;/** * 浅克隆测试 *  * @author 小明 * */public class ShallowCloneTest {    public static void main(String[] args) throws CloneNotSupportedException {        Address address = new Address("广东", "广州", "天河"); // 地址        Student stu1 = new Student("小明", 28, address); // 第一个学生对象        Student stu2 = (Student) stu1.clone(); // 第二个学生对象,为克隆第一个学生对象        // 修改第二个学生对象的信息        stu2.setName("王飞鸿");        stu2.setAge(35);        stu2.getAddress().setProvince("四川");        stu2.getAddress().setCity("成都");        stu2.getAddress().setDetail("青羊区");        // 打印第一个学生对象的信息        System.out.println(stu1);    }}

运行结果:

Student [name=小明, age=28, address=Address [province=四川, city=成都, detail=青羊区]]

从运行结果看到,我们仅只修改了第二个学生对象的地址,但第一个学生对象的地址也改变了,这说明两个学生对象是共享的学生地址对象。

那如何实现深克隆呢?

4. 深克隆

地址类:

package test.clone;/** * 地址类 *  * @author 小明 * */public class Address implements Cloneable {    private String province; // 省    private String city; // 市    private String detail; // 详细地址    public Address() {        super();    }    public Address(String province, String city, String detail) {        super();        this.province = province;        this.city = city;        this.detail = detail;    }    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;    }    public String getDetail() {        return detail;    }    public void setDetail(String detail) {        this.detail = detail;    }    @Override    public String toString() {        return "Address [province=" + province + ", city=" + city + ", detail="                + detail + "]";    }    @Override    public Object clone() throws CloneNotSupportedException {        return super.clone();    }}

学生类:

package test.clone;/** * 学生类 *  * @author 小明 * */public class Student implements Cloneable {    private String name; // 姓名    private int age; // 年龄    private Address address; // 地址    public Student() {        super();    }    public Student(String name, int age, Address address) {        super();        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() {        return "Student [name=" + name + ", age=" + age + ", address="                + address + "]";    }    @Override    public Object clone() throws CloneNotSupportedException {        Student stu = (Student) super.clone();        stu.address = (Address) address.clone();        return stu;    }}

测试类:

package test.clone;/** * 深克隆测试 *  * @author 小明 * */public class DeepCloneTest {    public static void main(String[] args) throws CloneNotSupportedException {        Address address = new Address("广东", "广州", "天河"); // 地址        Student stu1 = new Student("小明", 28, address); // 第一个学生对象        Student stu2 = (Student) stu1.clone(); // 第二个学生对象,为克隆第一个学生对象        // 修改第二个学生对象的信息        stu2.setName("王飞鸿");        stu2.setAge(35);        stu2.getAddress().setProvince("四川");        stu2.getAddress().setCity("成都");        stu2.getAddress().setDetail("青羊区");        // 打印第一个学生对象的信息        System.out.println(stu1);        // 打印第二个学生对象的信息        System.out.println(stu2);    }}

运行结果:

Student [name=小明, age=28, address=Address [province=广东, city=广州, detail=天河]]Student [name=王飞鸿, age=35, address=Address [province=四川, city=成都, detail=青羊区]]

从运行结果中看出,修改第二个学生对象时,第一个学生对象的地址并不受影响,说明克隆学生对象时,不仅克隆了学生对象,也克隆了其子对象。

5. 利用串行化实现深克隆

地址类:

package test.clone2;import java.io.Serializable;/** * 地址类 *  * @author 小明 * */public class Address implements Serializable {    private String province; // 省    private String city; // 市    private String detail; // 详细地址    public Address() {        super();    }    public Address(String province, String city, String detail) {        super();        this.province = province;        this.city = city;        this.detail = detail;    }    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;    }    public String getDetail() {        return detail;    }    public void setDetail(String detail) {        this.detail = detail;    }    @Override    public String toString() {        return "Address [province=" + province + ", city=" + city + ", detail="                + detail + "]";    }}

学生类:

package test.clone2;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;/** * 学生类 *  * @author 小明 * */public class Student implements Serializable {    private String name; // 姓名    private int age; // 年龄    private Address address; // 地址    public Student() {        super();    }    public Student(String name, int age, Address address) {        super();        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() {        return "Student [name=" + name + ", age=" + age + ", address="                + address + "]";    }    /**     * 利用串行化深克隆     *      * @return 深克隆后的对象     */    public Object deepClone() {        ObjectOutputStream oos = null;        ObjectInputStream ois = null;        try {            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();            oos = new ObjectOutputStream(byteArrayOutputStream);            oos.writeObject(this);            ois = new ObjectInputStream(new ByteArrayInputStream(                    byteArrayOutputStream.toByteArray()));            return ois.readObject();        } catch (Exception e) {            throw new RuntimeException(e);        } finally {            try {                if (oos != null)                    oos.close();                if (ois != null)                    ois.close();            } catch (IOException e) {                throw new RuntimeException(e);            }        }    }}

测试类:

package test.clone2;/** * 深克隆测试 *  * @author 小明 * */public class DeepCloneTest {    public static void main(String[] args) throws CloneNotSupportedException {        Address address = new Address("广东", "广州", "天河"); // 地址        Student stu1 = new Student("小明", 28, address); // 第一个学生对象        Student stu2 = (Student) stu1.deepClone(); // 第二个学生对象,为克隆第一个学生对象        // 修改第二个学生对象的信息        stu2.setName("王飞鸿");        stu2.setAge(35);        stu2.getAddress().setProvince("四川");        stu2.getAddress().setCity("成都");        stu2.getAddress().setDetail("青羊区");        // 打印第一个学生对象的信息        System.out.println(stu1);        // 打印第二个学生对象的信息        System.out.println(stu2);    }}

运行结果:

Student [name=小明, age=28, address=Address [province=广东, city=广州, detail=天河]]Student [name=王飞鸿, age=35, address=Address [province=四川, city=成都, detail=青羊区]]

说明:利用串行化实现深克隆,克隆对象与子对象对应的类都必须实现java.io.Serializable接口。

0 0
原创粉丝点击