带你详细了解clone方法

说到clone,工作中可能使用到的不多,所以今天就给大家讲一下。

clone方法是Object类的一个方法可能大家都知道,但是可能很多人都没有注意到clone方法的修饰符,我们来看一下源码

public class Object {

     * @throws  CloneNotSupportedException  if the object's class does not
     *               support the {@code Cloneable} interface. Subclasses
     *               that override the {@code clone} method can also
     *               throw this exception to indicate that an instance cannot
     *               be cloned.
    protected native Object clone() throws CloneNotSupportedException;
}

得出以下三个结论:
- clone是一个native方法,而不是java方法,所以可以通过这个修饰符得出结论,clone方法并不会像java一样new一个新对象出来,而是创建一个新的对象,将原对象的数据复制了一份
- clone方法的修饰符是protected,所以任意对象想要调用clone方法,必须自己实现clone方法
- clone方法会抛出CloneNotSupportedException异常。通过注释,我们可以知道只有实现了Cloneable接口的类才能调用clone方法,否则会抛出CloneNotSupportedException异常

接下来我们详细讲一下clone方法的复制过程
我们先来看一下下面这个测试用例:

public class MyTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        User user = new User(new Hobby());
        User user2 = (User)user.clone();
        System.out.println(user == user2);
        System.out.println(user.getHobby() == user2.getHobby());
    }
}

class User implements Cloneable{

    private Hobby hobby;

    public User(Hobby hobby) {
        super();
        this.hobby = hobby;
    }

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

    public Hobby getHobby() {
        return hobby;
    }

}

class Hobby{

    public Hobby() {
        super();
    }

}
  • 因为user != user2,所以我们可以知道,clone方法并不是创建一个新的变量user2,用于指向原对象user的内存地址,而是开辟了一块新的内存,创建了一个新的对象
  • 因为user.getHobby() == user2.getHobby(),所以我们可以知道,Object类的clone方法对于复制User类的hobby属性,没有new一个新的对象,而是直接引用了原对象hobby属性的地址

得出结论,Object类的clone方法,对于成员变量引用的其他对象不会创建一个新的对象,只是引用原对象的地址,术语上叫浅层复制。而如果我们想将引用对象也复制一份,而不是单纯的引用地址,就需要深层复制

那么怎样去实现深层复制呢?可以去重写User的clone方法,使得在复制User对象的时候也将Hobby对象复制一份

class User implements Cloneable{

    private Hobby hobby;

    public User(Hobby hobby) {
        super();
        this.hobby = hobby;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        User user = (User)super.clone();
        user.hobby = (Hobby)hobby.clone();
        return user;
    }

    public Hobby getHobby() {
        return hobby;
    }

}

class Hobby implements Cloneable{

    public Hobby() {
        super();
    }

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

}

我们在调用User的clone方法的时候,会先去调用Hobby的clone方法,这样就能保证复制出来的User对象的Hobby属性是也是一个新的的对象。

看起来重写了User的clone方法就实现了我们想要的深层复制,但是如果Hobby类的成员变量也有引用,引用一个Music对象怎么办呢?似乎只能再重写Hobby的clone方法。

这样就陷入一个无限循环,所以clone方法理论上是不存在绝对的深层复制的。

那么如果说,我就想实现一个绝对的深层复制,怎么办呢?

有时候思路不能局限于一个方法,如果想从clone方法上找解决方案,多半是不现实的了。

开阔一下思维就能想到可以使用序列化来实现深层复制,序列化和反序列化生成的对象以及对象的属性一定都是新的对象,而不是对原对象地址的引用,下面给出针对上面User类的复制代码(类必须实现Serializable接口)

class User implements Serializable {

    private static final long serialVersionUID = 1L;

    private Hobby hobby;

    public Object deepClone() throws IOException, OptionalDataException, ClassNotFoundException {// 将对象写到流里
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream oo = new ObjectOutputStream(bo);
        oo.writeObject(this);
        ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
        ObjectInputStream oi = new ObjectInputStream(bi);
        return (oi.readObject());
    }

    public User(Hobby hobby) {
        super();
        this.hobby = hobby;
    }

    public Hobby getHobby() {
        return hobby;
    }

}

class Hobby implements Serializable {

    private static final long serialVersionUID = 1L;

    public Hobby() {
        super();
    }

}

关于clone方法、浅层复制以及深层复制的分享到这里就结束了,希望对大家有所帮助。

扫码关注,不迷路
扫码关注

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Ubuntu中,如果在执行git clone命令时连接失败,可能有几个原因导致。首先,可能是由于网络问题导致无法连接到GitHub服务器。其次,可能是由于GitHub的地址发生了变化,导致原有的地址无法访问。最后,可能是由于使用了不正确的协议或配置。 要解决这个问题,可以按照以下步骤进行操作: 1. 确保你的*** 2. 如果ping命令失败或显示连接被拒绝的错误信息,那可能是GitHub服务器的地址发生了变化。你可以使用IP查询工具来获取最新的GitHub服务器地址,并更新你的git配置文件。参考中提供的链接可以了解如何使用IP查询工具以及如何更新git配置文件。 3. 如果你尝试使用git://协议进行克隆时出现连接失败的错误,可以尝试使用https://协议来替代。执行以下命令来配置git使用https协议:git config --global url."https://".insteadof git://。参考提供的链接了解更多详细信息。 4. 如果以上方法都无效,还可以参考提供的链接中的博文,里面提供了一些其他解决方法和参考文章。 综上所述,这是解决Ubuntu中git clone连接失败的一些可能方法和步骤。你可以根据具体情况选择适合你的解决方案。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [ubuntu18.04 git clone:Failed to connect to github.com port 443: Connection refused](https://blog.csdn.net/qq_38204686/article/details/123444765)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [【已解决】Ubuntu下git clone 无法连接问题](https://blog.csdn.net/YSBJ123/article/details/50595218)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值