Java_Cloneable 接口浅析

336 阅读2分钟

1. 概念

只是一个标记接口,本身并未抽象方法,被标记的对象会由Object使用本地方法来实现拷贝(浅拷贝)。

2. 使用

需要在要可以被拷贝的对象中

  1. 实现Cloneable接口(不实现就调用clone方法,会抛出CloneNotSupportedException克隆不被支持异常)
  2. 重写Object中的clone方法(不重写则使用Object中的clone方法,为浅拷贝)

在要拷贝处调用clone()方法

2.1. 使用Object中的clone方法实现浅拷贝实例


import lombok.AllArgsConstructor;
import lombok.SneakyThrows;  

@AllArgsConstructor  
public class Human implements Cloneable{  
    String name;  
    Dog dog;   
  
    @Override  
    public String toString(){
        return "Human(name=" + name+",Dog="+dog+",hash="+this.hashCode()+")";
    }  
  
    @SneakyThrows  
    public static void main(String[] args) {  
        Human lian = new Human("Lian",new Dog("Lucky"));  
        Human clone = (Human) lian.clone();  
        System.out.println(lian);  
        System.out.println(clone);  
    }  
}
@AllArgsConstructor
class Dog {
    String name;
    @Override  
    public String toString(){
        return "Dog(name=" + name+",hash="+this.hashCode()+")";
    }  
}

结果为:

Human(name=Lian,Dog=Dog(name=Lucky,hash=1134517053),hash=835648992)
Human(name=Lian,Dog=Dog(name=Lucky,hash=1134517053),hash=492228202)

此时Dog是同一个,Human则是不同的两个实例。

2.2. 使用自定义方法实现拷贝

import lombok.AllArgsConstructor;  
import lombok.SneakyThrows;  
  
@AllArgsConstructor  
public class Human implements Cloneable {  
    String name;  
    Dog dog;  
  
    @Override  
    protected Object clone() throws CloneNotSupportedException {  
        Human clone = (Human) super.clone();  
        clone.dog=(Dog)dog.clone();  
        return clone;  
    }  
  
    @Override  
    public String toString() {  
        return "Human(name=" + name + ",Dog=" + dog + ",hash=" + this.hashCode() + ")";  
    }  
  
    @SneakyThrows  
    public static void main(String[] args) {  
        Human lian = new Human("Lian", new Dog("Lucky"));  
        Human clone = (Human) lian.clone();  
        System.out.println(lian);  
        System.out.println(clone);  
    }  
}  
@AllArgsConstructor  
class Dog implements Cloneable{  
    String name;  
  
    @Override  
    protected Object clone() throws CloneNotSupportedException {  
        return super.clone();  
    }  
  
    @Override  
    public String toString() {  
        return "Dog(name=" + name + ",hash=" + this.hashCode() + ")";  
    }  
}

结果为:

Human(name=Lian,Dog=Dog(name=Lucky,hash=140435067),hash=1450495309)
Human(name=Lian,Dog=Dog(name=Lucky,hash=1670782018),hash=1706377736)

这时Human持有的Dog对象也是新的实例了。

3. Tip

浅拷贝和深拷贝的区别:拷贝对象的时候,对对象中对象字段这种引用数据类型的操作不同。深拷贝会继续解析引用的类型生成新的实例,再次进行深拷贝,一直递归下去。浅拷贝只会把引用类型的地址赋值到拷贝实例中,不会生成其他的实例对象。

4. 参考:

Cloneable接口的作用与深入理解深度克隆与浅度克隆