工作三年,小胖连 Clone 源码都没读过?真的菜!(下)

简介: 工作三年,小胖连 Clone 源码都没读过?真的菜!

5. 深克隆还有哪些实现方式?


深克隆的实现方式很多,总的来说有以下几种:


  • 所有对象都实现克隆方法。
  • 通过构造方法实现深克隆。
  • 使用 JDK 自带的字节流。
  • 使用第三方工具实现,比如:Apache Commons Lang。
  • 使用 JSON 工具类实现,比如:Gson,FastJSON 等等。


1、有对象都实现克隆方法


/**
 * Project Name:review_java <br/>
 * Package Name:com.nasus.clone <br/>
 * Date:2021/1/31 20:57 <br/>
 *
 * @author <a href="turodog@foxmail.com">chenzy</a><br/>
 */
public class DeepCloneOneExample {
    static class User implements Cloneable {
        public User() {
        }
        public User(Integer age, String name, Address address) {
            this.age = age;
            this.name = name;
            this.address = address;
        }
        // 年龄
        private Integer age;
        // 名称
        private String name;
        // 地址
        private Address address;
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Address getAddress() {
            return address;
        }
        public void setAddress(Address address) {
            this.address = address;
        }
        @Override
        protected Object clone() throws CloneNotSupportedException {
            User user = (User) super.clone();
            // 引用类型克隆赋值
            user.setAddress((Address) this.address.clone());
            return user;
        }
    }
    static class Address implements Cloneable {
        public Address() {
        }
        public Address(String province, String city) {
            this.province = province;
            this.city = city;
        }
        // 省份
        private String province;
        // 城市
        private String 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 (Address) super.clone();
        }
    }
    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建被赋值对象
        Address address = new Address("广东", "广州");
        User userOne = new User(22, "clone", address);
        // 克隆 userOne 对象
        User userTwo = (User) userOne.clone();
        // 修改原型对象
        userOne.getAddress().setCity("清远");
        // 输出 p1 和 p2 地址信息
        System.out.println("userOne:" + userOne.getAddress().getCity() +
                ",userTwo:" + userTwo.getAddress().getCity());
    }
}


运行结果:


userOne:清远,userTwo:广州


可以看到,修改了原型对象的引用对象并没有改变克隆对象的引用对象。说明两者引用对象已经不是同一个引用对象了,所以是深克隆。


2、通过构造方法实现深克隆


《Effective Java》 中「推荐使用构造器(Copy Constructor)来实现深克隆,如果构造器的参数为基本数据类型或字符串类型则直接赋值,如果是对象类型,则需要重新 new 一个对象」,实现代码如下:


/**
 * Project Name:review_java <br/>
 * Package Name:com.nasus.clone <br/>
 * Date:2021/1/31 21:16 <br/>
 *
 * @author <a href="turodog@foxmail.com">chenzy</a><br/>
 */
public class DeepCloneSecondExample {
    static class User {
        public User() {
        }
        public User(Integer age, String name, Address address) {
            this.age = age;
            this.name = name;
            this.address = address;
        }
        // 年龄
        private Integer age;
        // 名称
        private String name;
        // 地址
        private Address address;
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Address getAddress() {
            return address;
        }
        public void setAddress(Address address) {
            this.address = address;
        }
    }
    static class Address {
        public Address() {
        }
        public Address(String province, String city) {
            this.province = province;
            this.city = city;
        }
        // 省份
        private String province;
        // 城市
        private String 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;
        }
    }
    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建对象
        Address address = new Address("广东", "广州");
        User userOne = new User(22, "clone", address);
        // 调用构造函数克隆对象
        User userTwo = new User(userOne.getAge(), userOne.getName(),
                new Address(userOne.getAddress().getProvince(), userOne.getAddress().getCity()));
        // 修改原型对象
        userOne.getAddress().setCity("清远");
        // 输出 userOne 和 userOne 地址信息
        System.out.println("userOne:" + userOne.getAddress().getCity() +
                ",userTwo:" + userTwo.getAddress().getCity());
    }
}


运行结果:


userOne:清远,userTwo:广州


3、使用 JDK 自带的字节流


使用 JDK 自带字节流实现,先将要原型对象写入到内存中的字节流,再从这个字节流中读出刚刚存储的信息,作为一个新对象返回,此时这个新对象和原型对象就不存在任何地址上的共享,从而实现深克隆,代码如下:


/**
 * Project Name:review_java <br/>
 * Package Name:com.nasus.clone <br/>
 * Date:2021/1/31 21:25 <br/>
 *
 * @author <a href="turodog@foxmail.com">chenzy</a><br/>
 */
public class DeepCloneThirdExample {
    static class User implements Serializable{
        public User() {
        }
        public User(Integer age, String name, Address address) {
            this.age = age;
            this.name = name;
            this.address = address;
        }
        // 年龄
        private Integer age;
        // 名称
        private String name;
        // 地址
        private Address address;
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Address getAddress() {
            return address;
        }
        public void setAddress(Address address) {
            this.address = address;
        }
    }
    static class Address implements Serializable {
        public Address() {
        }
        public Address(String province, String city) {
            this.province = province;
            this.city = city;
        }
        // 省份
        private String province;
        // 城市
        private String 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;
        }
    }
    /**
     * 通过字节流实现克隆
     */
    static class StreamClone {
        public static <T extends Serializable> T clone(User user) {
            T cloneObj = null;
            try {
                // 写入字节流
                ByteArrayOutputStream bo = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(bo);
                oos.writeObject(user);
                oos.close();
                // 分配内存,写入原始对象,生成新对象
                // 获取上面的输出字节流
                ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
                ObjectInputStream oi = new ObjectInputStream(bi);
                // 返回生成的新对象
                cloneObj = (T) oi.readObject();
                oi.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return cloneObj;
        }
    }
    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建对象
        Address address = new Address("广东", "广州");
        User userOne = new User(22, "clone", address);
        // 调用构造函数克隆对象
        User userTwo = StreamClone.clone(userOne);
        // 修改原型对象
        userOne.getAddress().setCity("清远");
        // 输出 userOne 和 userOne 地址信息
        System.out.println("userOne:" + userOne.getAddress().getCity() +
                ",userTwo:" + userTwo.getAddress().getCity());
    }
}


运行结果:


userOne:清远,userTwo:广州


结果还是一样的,但这里要注意下。由于是通过字节流序列化实现的深克隆,所以每个对象必须能被序列化。也即必须实现 Serializable 接口。


4、通过第三方工具实现深克隆


比如:Apache Commons Lang,实现代码如下:


/**
 * Project Name:review_java <br/>
 * Package Name:com.nasus.clone <br/>
 * Date:2021/1/31 21:41 <br/>
 *
 * @author <a href="turodog@foxmail.com">chenzy</a><br/>
 */
public class DeepCloneFourthExample {
    static class User implements Serializable {
        public User() {
        }
        public User(Integer age, String name, Address address) {
            this.age = age;
            this.name = name;
            this.address = address;
        }
        // 年龄
        private Integer age;
        // 名称
        private String name;
        // 地址
        private Address address;
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Address getAddress() {
            return address;
        }
        public void setAddress(Address address) {
            this.address = address;
        }
    }
    static class Address implements Serializable {
        public Address() {
        }
        public Address(String province, String city) {
            this.province = province;
            this.city = city;
        }
        // 省份
        private String province;
        // 城市
        private String 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;
        }
    }
    public static void main(String[] args) {
        // 创建对象
        Address address = new Address("广东", "广州");
        User userOne = new User(22, "clone", address);
        // 调用 apache.commons.lang 克隆对象
        User userTwo = SerializationUtils.clone(userOne);
        // 修改原型对象
        userOne.getAddress().setCity("清远");
        // 输出 userOne 和 userOne 地址信息
        System.out.println("userOne:" + userOne.getAddress().getCity() +
                ",userTwo:" + userTwo.getAddress().getCity());
    }
}


输出结果:


userOne:清远,userTwo:广州


实际上,这种工作中我自己是用的比较多的一种方法。因为方便,它跟第三种有点像。其实底层是一样的,还是李用字节流实现。


5、使用 JSON 工具类实现


比如 Gson 或者 FastJson 等等,下面以 Gson 为例,实现代码如下:


/**
 * Project Name:review_java <br/>
 * Package Name:com.nasus.clone <br/>
 * Date:2021/1/31 21:58 <br/>
 *
 * @author <a href="turodog@foxmail.com">chenzy</a><br/>
 */
public class DeepCloneFifthExample {
    static class User {
        public User() {
        }
        public User(Integer age, String name, Address address) {
            this.age = age;
            this.name = name;
            this.address = address;
        }
        // 年龄
        private Integer age;
        // 名称
        private String name;
        // 地址
        private Address address;
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Address getAddress() {
            return address;
        }
        public void setAddress(Address address) {
            this.address = address;
        }
    }
    static class Address {
        public Address() {
        }
        public Address(String province, String city) {
            this.province = province;
            this.city = city;
        }
        // 省份
        private String province;
        // 城市
        private String 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;
        }
    }
    public static void main(String[] args) {
        // 创建对象
        Address address = new Address("广东", "广州");
        User userOne = new User(22, "clone", address);
        // 调用 Gson 克隆对象
        Gson gson = new Gson();
        User userTwo = gson.fromJson(gson.toJson(userOne), User.class);
        // 修改原型对象
        userOne.getAddress().setCity("清远");
        // 输出 userOne 和 userTwo 地址信息
        System.out.println("userOne:" + userOne.getAddress().getCity() +
                ",userTwo:" + userTwo.getAddress().getCity());
    }
}


运行结果:


userOne:清远,userTwo:广州


这种方法会先把对象转化成字符串,再从字符串转化成新的对象,因为新对象是从字符串转化而来的,因此不会和原型对象有任何的关联,所以实现了深克隆。


6. 总结


本文介绍了深浅克隆的概念、区别;怎么实现客隆;克隆有啥约定俗成的规则;


Arrays.copy () 是深克隆还是浅克隆;以及深刻龙的几种实现方式。希望对你有帮助~


相关文章
|
2天前
|
弹性计算 运维 搜索推荐
三翼鸟携手阿里云ECS g9i:智慧家庭场景的效能革命与未来生活新范式
三翼鸟是海尔智家旗下全球首个智慧家庭场景品牌,致力于提供覆盖衣、食、住、娱的一站式全场景解决方案。截至2025年,服务近1亿家庭,连接设备超5000万台。面对高并发、低延迟与稳定性挑战,全面升级为阿里云ECS g9i实例,实现连接能力提升40%、故障率下降90%、响应速度提升至120ms以内,成本降低20%,推动智慧家庭体验全面跃迁。
|
3天前
|
数据采集 人工智能 自然语言处理
3分钟采集134篇AI文章!深度解析如何通过云无影AgentBay实现25倍并发 + LlamaIndex智能推荐
结合阿里云无影 AgentBay 云端并发采集与 LlamaIndex 智能分析,3分钟高效抓取134篇 AI Agent 文章,实现 AI 推荐、智能问答与知识沉淀,打造从数据获取到价值提炼的完整闭环。
351 91
|
10天前
|
人工智能 自然语言处理 前端开发
Qoder全栈开发实战指南:开启AI驱动的下一代编程范式
Qoder是阿里巴巴于2025年发布的AI编程平台,首创“智能代理式编程”,支持自然语言驱动的全栈开发。通过仓库级理解、多智能体协同与云端沙箱执行,实现从需求到上线的端到端自动化,大幅提升研发效率,重塑程序员角色,引领AI原生开发新范式。
854 156
|
3天前
|
数据采集 缓存 数据可视化
Android 无侵入式数据采集:从手动埋点到字节码插桩的演进之路
本文深入探讨Android无侵入式埋点技术,通过AOP与字节码插桩(如ASM)实现数据采集自动化,彻底解耦业务代码与埋点逻辑。涵盖页面浏览、点击事件自动追踪及注解驱动的半自动化方案,提升数据质量与研发效率,助力团队迈向高效、稳定的智能化埋点体系。(238字)
258 156
|
4天前
|
域名解析 人工智能
【实操攻略】手把手教学,免费领取.CN域名
即日起至2025年12月31日,购买万小智AI建站或云·企业官网,每单可免费领1个.CN域名首年!跟我了解领取攻略吧~
|
11天前
|
机器人 API 调度
基于 DMS Dify+Notebook+Airflow 实现 Agent 的一站式开发
本文提出“DMS Dify + Notebook + Airflow”三位一体架构,解决 Dify 在代码执行与定时调度上的局限。通过 Notebook 扩展 Python 环境,Airflow实现任务调度,构建可扩展、可运维的企业级智能 Agent 系统,提升大模型应用的工程化能力。
|
人工智能 前端开发 API
前端接入通义千问(Qwen)API:5 分钟实现你的 AI 问答助手
本文介绍如何在5分钟内通过前端接入通义千问(Qwen)API,快速打造一个AI问答助手。涵盖API配置、界面设计、流式响应、历史管理、错误重试等核心功能,并提供安全与性能优化建议,助你轻松集成智能对话能力到前端应用中。
816 154