欢迎访问宙启技术站
智能推送

Java中的clone()函数:如何复制一个对象?

发布时间:2023-06-17 07:16:16

在Java中,我们可以使用clone()函数来复制一个对象。clone()函数是一个基本函数,用于创建对象的副本。它实现了深拷贝,即创建一个新对象并复制原对象的所有字段。这样,新对象就拥有了原对象的所有属性和方法,但是它们指向的是不同的内存地址。下面我们来详细讲解如何使用clone()函数。

一、使用clone()函数的前提条件

要使用clone()函数,我们必须满足以下三个条件:

1. 必须要实现Cloneable接口。这个接口是一个标记接口,表明这个类是可克隆的。

2. 实现一个public的clone()函数并进行覆盖。

3. 保证对象中的域也都是可克隆的。

不满足上述条件,直接调用clone()函数将会抛出CloneNotSupportedException异常。

二、实现clone()函数的步骤

1. 实现Cloneable接口。这个步骤非常简单,只需要在类的声明中加上implements Cloneable即可。

2. 在类中添加一个public的clone()函数并进行覆盖。注意,这个方法必须要使用public修饰符。

3. 在clone()函数中使用super.clone()方法来调用父类的clone()函数,并将结果强制转换成当前类的对象返回即可。

4. 对于非基本类型的域,要递归地调用它的clone()函数。

三、克隆的两种方式

1. 浅拷贝

浅拷贝是指复制对象时,我们只复制对象引用,而不是对象本身。也就是说,我们得到的是一个新对象,但其引用的数据是和原对象相同的。

下面是一个浅拷贝的例子:

public class Person implements Cloneable {
    public String name;
    public int age;
    public Address address;
    
    public Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
    
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Address implements Cloneable {
    public String street;
    public String city;
    
    public Address(String street, String city) {
        this.street = street;
        this.city = city;
    }
    
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("123 Main St", "Anytown");
        Person person1 = new Person("Alice", 30, address);
        Person person2 = (Person) person1.clone();
        
        System.out.println(person1.address.street == person2.address.street); // true
    }
}

我们在Person类中包含了一个Address类的引用,然后将Person对象进行克隆。可以看到,person1和person2的address域都指向相同的对象。

2. 深拷贝

深拷贝是指复制对象时,我们不仅复制对象本身,还复制其引用的数据。这样,我们得到的是一个新对象,其所有数据都和原对象完全不同。

下面是一个深拷贝的例子:

public class Person implements Cloneable {
    public String name;
    public int age;
    public Address address;
    
    public Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
    
    public Object clone() throws CloneNotSupportedException {
        Person person = (Person) super.clone(); // 调用父类的clone()函数
        
        person.address = (Address) address.clone(); // 克隆Address类
        
        return person;
    }
}

public class Address implements Cloneable {
    public String street;
    public String city;
    
    public Address(String street, String city) {
        this.street = street;
        this.city = city;
    }
    
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("123 Main St", "Anytown");
        Person person1 = new Person("Alice", 30, address);
        Person person2 = (Person) person1.clone();
        
        System.out.println(person1.address.street == person2.address.street); // false
    }
}

这次,我们在Person类中的clone()函数中调用了Address类的clone()函数,这样就实现了深拷贝。可以看到,person1和person2的address域现在指向不同的对象。

四、clone()函数的注意事项

1. 在类中覆盖clone()函数时,必须要使用public修饰符。

2. 调用super.clone()函数来调用父类的clone()函数时,必须要将其结果进行强制转换成当前类的对象。

3. clone()函数并不是一个构造函数,它并不会调用构造函数。

4. 最好使用浅拷贝的方式来克隆基本类型的域,使用深拷贝的方式来克隆非基本类型的域。

总之,我们在使用clone()函数时,要注意上述的前提条件和注意事项,才能保证正确地复制对象。