java学习笔记-clone()方法相关知识

克隆的意义

如果一个对象A是引用类型,那么A中保存的信息是这个对象的堆地址,在程序中,有可能会出现这样的情况:某时某刻,我需要两个状态相同的对象,但是在此后的执行过程中分别执行不同的程序逻辑,然后得到两个状态不相同的对象。如果这时使用 B = A来得到A,B两个对象,是不行的,因为这两个对象实际上在内存中是指向同一个地址,之后的逻辑也针对这一个地址中的对象进行操作。这时候就需要用到clone()方法。

简单实现克隆

clone()方法是Object类中的一个受保护的,native的方法,并且要抛出一个CloneNotSupportedException,受保护说明这个clone只能被同一个包或者Object类的子类对象调用,native就先不考虑方法的底层实现,抛出CloneNotSupportedException异常,一般是两种情况,第一是要实现克隆的类没有实现Cloneable接口(提一句,Cloneable是一个标记接口,里面并没有需要实现的方法,只是告诉虚拟机一个信息,要有这个概念),会抛出异常,第二种是实现克隆的类中有域无法克隆(这种情况我还没有实际实现过)

import entity.User;

public class ZhengZe {
    public static void main(String[] args) throws CloneNotSupportedException {
        User user = new User(1234,"zhangsan");
        user.clone();
    }
}
package entity;

public class User implements Cloneable{
    private Integer id ;
    private String name;

    public User() {
    }

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

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

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

上面代码是很简单实现克隆的方式,可以看到User实体类中重写了clone方法,并且实现了Cloneable接口,实现接口的作用是为了不报异常,重写是因为Object类中clone方法是protected修饰,main方法所在的类ZhengZe不是java.lang 包中的类,并且ZhengZe是和User类一样继承Object类,子类中是无法调用相同父类对应的其他子类的protected修饰的方法的,所以必须在User类中重写clone方法。(这个地方不好理解,建议复习下修饰符相关知识)

实现深度克隆

深度克隆是什么意思呢,我们上面实现的克隆有个问题,现在User类中有id有name字段,假如说还有个地址address字段,地址需要分为省和市两部分,那address应该是个对象类型,这时通过clone克隆出来的对象,address的值和原对象的值是同一个地址,如果修改了其中一个对象的address,那么两个对象的address字段都会变化,这显然不是我们想要的结果,所以可以通过深度克隆解决这个问题。

import entity.Address;
import entity.User;

public class ZhengZe {
    public static void main(String[] args) throws CloneNotSupportedException {
        User user = new User(1234,"zhangsan",new Address("河北省","石家庄市"));
        User copy = (User) user.clone();
        System.out.println(user);
        System.out.println(user.getAddress());
        System.out.println(copy);
        System.out.println(copy.getAddress());
    }
}

 

package entity;

public class User implements Cloneable{
    private Integer id ;
    private String name;
    private Address address;

    public User() {
    }

    public User(Integer id, String name, Address address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public Object clone() throws CloneNotSupportedException {
        User user = (User)super.clone();
        user.address = (Address) user.address.clone();
        return user;
    }

}

 

package entity;

public class Address implements Cloneable{
    private String province;
    private String city;

    public Address() {
    }

    public Address(String province, String city) {
        this.province = province;
        this.city = city;
    }

    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;
    }

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

上述代码中使用了深度克隆的方式,可以看到Address类中也重写了clone方法,然后User类中的clone方法进行更新,将克隆对象的Address也进行克隆,根据输出的地址可以判断,无论是User对象,还是Address对象,都是不相同的,也可以修改代码测试不克隆Address类对象的情况,这里不赘述了。

所以在实际的应用中,要注意的几点:

  • 类是否支持克隆
  • 实现Cloneable接口
  • 重写clone方法
  • 类的域中是否有可变对象,如果有影响,需要进行深度克隆
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值