java中的clone()方法详解

今天在看阿里巴巴java开发手册时看到这么一个规范不太理解在这里插入图片描述因为平时clone方法也用的比较少。所以去看了下java的api文档。总结了一下java中clone()方法。
我们在对象的赋值其实就是复制了引用对象的内存地址:

@Test
public void testassign(){
  Person p1=new Person();
  p1.setAge(31);
  p1.setName("Peter");
 
  Person p2=p1;
  System.out.println(p1==p2);//true

但是当我们想一开始对象有相同的初始状态,然后修改不同的属性方法,对象之间相互不影响,这时候就需要java中的clone()方法了。

java中的api文档是这么写的
在这里插入图片描述
我们可以看到克隆后的对象与被复制的对象是不相等的,==的比较是地址的比较,说明对象的clone没有引用之前的地址了。后面的叙述有点不容易理解,其实说白了就是克隆clone()方法中浅拷贝和深度拷贝的问题。如果一个实体类想要克隆一个对象,首先要实现Cloneable()的接口,重写clone()方法。当该实体类只有基本类型字段或不变对象的引用时,我们不需要在clone()方法中重写该成员属性的克隆逻辑,如果有的话,则需要重写该成员属性的克隆逻辑。现在上代码。

@Data
public class Person implements Cloneable {
    private String name;
    private Integer age;
    private Address address;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
 
@Test
public void testShallowCopy() throws Exception{
  Person p1=new Person();
  p1.setAge(31);
  p1.setName("Peter");
 
  Person p2=(Person) p1.clone();
  System.out.println(p1==p2);//false
  p2.setName("Jacky");
  System.out.println("p1="+p1);//p1=Person [name=Peter, age=31]
  System.out.println("p2="+p2);//p2=Person [name=Jacky, age=31]
}

如果是基本数据类型的成员变量,我们克隆之后彼此的属性是可以相互不影响的,接着看:
如果增加一个自定义的类对象时

@Data
public class Address {
    private String type;
    private String value;
}

测试

@Test
public void testShallowCopy() throws Exception{
  Address address=new Address();
  address.setType("Home");
  address.setValue("北京");
 
  Person p1=new Person();
  p1.setAge(31);
  p1.setName("Peter");
  p1.setAddress(address);
 
  Person p2=(Person) p1.clone();
  System.out.println(p1==p2);//false
 
  p2.getAddress().setType("Office");
  System.out.println("p1="+p1);
  System.out.println("p2="+p2);
}

输出结果:

false
p1=Person(name=Peter, age=31, address=Address(type=Office, value=北京))
p2=Person(name=Peter, age=31, address=Address(type=Office, value=北京))

这是我们可以发现当我对p2对象进行操作的时候,p1对象中Address的值也发生了改变,这就是浅拷贝。其实p1对象中Address属性还是引用了p2中的地址。所以p2一改p1也跟着改变了。

前面实例中是浅拷贝和深拷贝的典型用例。

浅拷贝:被复制对象的所有值属性都含有与原来对象的相同,而所有的对象引用属性仍然指向原来的对象。

深拷贝:在浅拷贝的基础上,所有引用其他对象的变量也进行了clone,并指向被复制过的新对象。

也就是说,一个默认的clone()方法实现机制,仍然是赋值。

如果一个被复制的属性都是基本类型,那么只需要实现当前类的cloneable机制就可以了,此为浅拷贝。

如果被复制对象的属性包含其他实体类对象引用,那么这些实体类对象都需要实现cloneable接口并覆盖clone()方法。

@Data
public class Address implements Cloneable {
    private String type;
    private String value;
 
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
这样还不够,Person的clone()需要显式地clone其引用成员。

@Data
public class Person implements Cloneable {
    private String name;
    private Integer age;
    private Address address;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object obj=super.clone();
        Address a=((Person)obj).getAddress();
        ((Person)obj).setAddress((Address) a.clone());
        return obj;
    }
}

重新跑前面的测试用例:

false
p1=Person(name=Peter, age=31, address=Address(type=Home, value=北京))
p2=Person(name=Peter, age=31, address=Address(type=Office, value=北京)

现在克隆后的对象的属性就也不会跟着改变了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值