java基础-拷贝的认识

拷贝

为什么拷贝要实现Cloneable接口?

对象使用拷贝方法clone()是Object里面的方法,但是要在类上实现Cloneable接口。

该步骤其实和Serializable一样,本身是没有任何方法实现的,只是为了在执行的时候给JVM一个标志,告诉其实现该接口,从而能复写clone()方法。

public class User 
public class User implements Cloneable

public class LearnClone {
    public static void main(String[] args) throws CloneNotSupportedException {

        Object clone = new User("wzh").clone();

    }
}

从反编译看,有无实现Cloneable都是一样的步骤。下图第一个是没有实现Cloneable,第二次是实现Cloneable的。

在这里插入图片描述

没有实现Cloneable就去重写Object的clone方法,这是可以的。但是,在真正使用的时候,就会报CloneNotSupportedException

public class User {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

从Object看:

protected native Object clone() throws CloneNotSupportedException;

这个步骤和使用序列化的时候,实现Serializable接口是一个道理,只是为了让JVM进行识别。


常见拷贝方式

浅拷贝

复制例子

public class ShallowCloneExample implements Cloneable {
 private int[] arr;
 public ShallowCloneExample() {
 arr = new int[10];
 for (int i = 0; i < arr.length; i++) {
 arr[i] = i;
 }
 }
 public void set(int index, int value) {
 arr[index] = value;
 }
 public int get(int index) {
 return arr[index];
 }
    
 //浅拷贝的实现
 @Override
 protected ShallowCloneExample clone() throws CloneNotSupportedException
	{
 		return (ShallowCloneExample) super.clone();
 	}
}

ShallowCloneExample e1 = new ShallowCloneExample();
ShallowCloneExample e2 = null;
try {
 e2 = e1.clone();
} catch (CloneNotSupportedException e) {
 e.printStackTrace();
}
e1.set(2, 222);
System.out.println(e2.get(2)); // 22

详细讲解

拷⻉对象和原始对象的引⽤类型引⽤同⼀个对象,如果对象中有基本类型数值,直接复制。如果对象中有引用类型,其只是拷贝其引用类型的地址。
在这里插入图片描述

public class LearnClone {
    public static void main(String[] args) throws CloneNotSupportedException {

        User user = new User("wzh", new Person(18));
        User clone = (User)user.clone();

        //true
        System.out.println(user.getPerson().toString() == clone.getPerson().toString());

        //false
        System.out.println(user.toString() == clone.toString());

    }
}


public class User implements Cloneable{
    private String name;

    private Person person;

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    public User(String name, Person person) {
        this.name = name;
        this.person = person;

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;

    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}


public class Person {
    private Integer age;

    public Person(Integer age) {
        this.age = age;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

深拷贝

拷⻉对象和原始对象的引⽤类型引⽤不同对象。

在这里插入图片描述

复制例子

public class DeepCloneExample implements Cloneable {
 	private int[] arr;
 	public DeepCloneExample() {
 		arr = new int[10];
 		for (int i = 0; i < arr.length; i++) {
 			arr[i] = i;
 		}
 	}
    public void set(int index, int value) {
        arr[index] = value;
    }
    
    public int get(int index) {
        return arr[index];
    }
 //使用深拷贝,需要对引用类型字段逐一处理,过程比较繁琐  
 @Override
 protected DeepCloneExample clone() throws CloneNotSupportedException {
     //必不可少的步骤,调用Object.clone()方法。
 	DeepCloneExample result = (DeepCloneExample) super.clone();
 		result.arr = new int[arr.length];
 		for (int i = 0; i < arr.length; i++) {
 			result.arr[i] = arr[i];
 		}
 	return result;
 	}
}
DeepCloneExample e1 = new DeepCloneExample();
DeepCloneExample e2 = null;
try {
 e2 = e1.clone();
} catch (CloneNotSupportedException e) {
 e.printStackTrace();
}
e1.set(2, 222);
System.out.println(e2.get(2)); // 2

clone()的替代方案

使⽤ clone() ⽅法来拷⻉⼀个对象即复杂⼜有⻛险,它会抛出异常,并且还需要类型转换。Effective Java 书上讲到,最好不要去使⽤ clone(),可以使⽤拷⻉构造函数或者拷⻉⼯⼚来拷⻉⼀个对象。

public class CloneConstructorExample {
 private int[] arr;
 public CloneConstructorExample() {
 arr = new int[10];
 for (int i = 0; i < arr.length; i++) {
 arr[i] = i;
 }
 }
 public CloneConstructorExample(CloneConstructorExample original) {
 arr = new int[original.arr.length];
 for (int i = 0; i < original.arr.length; i++) {
 arr[i] = original.arr[i];
 }
 }
 public void set(int index, int value) {
 arr[index] = value;
 }
 public int get(int index) {
 return arr[index];
 }
}
CloneConstructorExample e1 = new CloneConstructorExample();
CloneConstructorExample e2 = new CloneConstructorExample(e1);
e1.set(2, 222);
System.out.println(e2.get(2)); // 2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值