Java对象克隆

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接口。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值