JavaSE---Object-clone()
一、概述
1 2 3 4 5 | /** * <what> * 创建并返回此对象的一个副本; * (按照原对象,创建一个新的对象[复制原对象的内容]) */ |
二、已经存在new或反射等技术,为啥还需要Object的clone方法?
1、new关键字、反射创建对象的弊端
1 2 3 4 5 6 7 8 | /** * 1、new关键字、反射创建对象的弊端 * 通过new、反射可以创建内容一样的对象; * 但是,创建对象之后,需要通过setter为新对象设置属性值,如果需要创建更多内容一样的对象,setter方法将不断重复; * * 解决: * 使用Object的clone方法; */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class User{ private String name; public String getName() { return name; } public void setName(String name) { this .name = name; } @Override public String toString() { return "User{" + "name='" + name + '\ '' + '}' ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | private static void newTest() { User user = new User(); user.setName( "rose" ); User userCopy = new User(); userCopy.setName(user.getName()); System.out.println(user); System.out.println(userCopy); } private static void reflectTest() throws ClassNotFoundException, IllegalAccessException, InstantiationException { User user = new User(); user.setName( "rose" ); Class<?> userClazz = Class.forName( "com.an.object.User" ); User userCopy = (User) userClazz.newInstance(); userCopy.setName(user.getName()); System.out.println(user); System.out.println(userCopy); } |
2、使用Object的clone方法
1 2 3 4 | /** * 1、需要调用clone方法的对象实现java.lang.Cloneable接口 * 2、重新clone方法 */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public class User implements Cloneable{ private String name; public String getName() { return name; } public void setName(String name) { this .name = name; } @Override public User clone() throws CloneNotSupportedException { return (User) super.clone(); } @Override public String toString() { return "User{" + "name='" + name + '\ '' + '}' ; } } |
1 2 3 4 5 6 7 8 9 10 11 | private static void cloneTest() throws CloneNotSupportedException { User user = new User(); user.setName( "rose" ); User userCopy = user.clone(); System.out.println(user); System.out.println(userCopy); } |
三、浅拷贝
1 2 3 4 5 6 7 8 9 | /** * <浅拷贝> * what * clone对象 是一个新对象 * clone对象的成员变量 与 原对象的成员变量 是同一个数据; * * 缺点 * 由于 原对象与clone对象 的成员变量 是同一个数据,任意一个对象对成员变量进行修改,原对象与clone对象的成员变量都会被修改; */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | public class User implements Cloneable{ private String name; private Man man; public String getName() { return name; } public void setName(String name) { this .name = name; } public Man getMan() { return man; } public void setMan(Man man) { this .man = man; } @Override public User clone() throws CloneNotSupportedException { return (User) super.clone(); } @Override public String toString() { return "User{" + "name='" + name + '\ '' + ", man=" + man + '}' ; } public static class Man{ private String job; public String getJob() { return job; } public void setJob(String job) { this .job = job; } @Override public String toString() { return "Man{" + "job='" + job + '\ '' + '}' ; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | private static void shallowClone() throws CloneNotSupportedException { User user = new User(); user.setName( "rose" ); User.Man man = new User.Man(); man.setJob( "teacher" ); user.setMan(man); User userCopy = user.clone(); System.out.println(user.getMan().hashCode()); // 1872034366 System.out.println(userCopy.getMan().hashCode()); // 1872034366 user.getMan().setJob( "coder" ); System.out.println(user.getMan()); // Man{job='coder'} System.out.println(userCopy.getMan()); // Man{job='coder'} } |
四、深拷贝
1、使用java.lang.Cloneable接口深拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /** * <深拷贝> * what * clone对象是一个新对象 * clone对象的成员变量 也是一个新对象; * * 步骤 * 1、原对象、原对象的成员变量 实现java.lang.Cloneable接口,重写clone方法 * 2、原对象的clone方法调用成员变量的clone方法; * * 使用java.lang.Cloneable接口实现深拷贝的弊端: * 成员变量重复实现java.lang.Cloneable接口 * 成员变量重复实现clone方法 * 原对象的clone方法重复改写 * * 解决 * 使用IO流的方式进行 深拷贝 * (解决重复修改源代码的问题) * */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | public class User implements Cloneable{ private String name; private Man man; public String getName() { return name; } public void setName(String name) { this .name = name; } public Man getMan() { return man; } public void setMan(Man man) { this .man = man; } @Override public User clone() throws CloneNotSupportedException { User clone = (User) super.clone(); clone.setMan(man.clone()); return clone; } @Override public String toString() { return "User{" + "name='" + name + '\ '' + ", man=" + man + '}' ; } public static class Man implements Cloneable{ private String job; public String getJob() { return job; } public void setJob(String job) { this .job = job; } @Override public Man clone() throws CloneNotSupportedException { return (Man) super.clone(); } @Override public String toString() { return "Man{" + "job='" + job + '\ '' + '}' ; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | private static void deepClone() throws CloneNotSupportedException { User user = new User(); user.setName( "rose" ); User.Man man = new User.Man(); man.setJob( "teacher" ); user.setMan(man); User userCopy = user.clone(); System.out.println(user.getMan().hashCode()); // 1872034366 System.out.println(userCopy.getMan().hashCode()); // 1581781576 user.getMan().setJob( "coder" ); System.out.println(user.getMan()); // Man{job='coder'} System.out.println(userCopy.getMan()); // Man{job='teacher'} } |
2、使用IO流深拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /** * <深拷贝-使用IO流> * API * ByteArrayOutputStream * ByteArrayInputStream * ObjectOutputStream * ObjectInputStream * 步骤 * 1、创建ByteArrayOutputStream,将数据转换为字节 * 2、创建ObjectOutputStream,关联ByteArrayOutputStream * 3、使用ObjectOutputStream的writeObject,读取要复制的对象 * 4、使用ByteArrayInputStream读取ByteArrayOutputStream转换的对象字节数据 * 5、创建ObjectInputStream读取对象字节数据,创建新的对象 * * 原对象及其变量需要实现java.io.Serializable接口 */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | package com.an.object; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** * @author apy * @description * @date 2022/4/24 17:22 */ public class User implements Serializable{ private String name; private Man man; public String getName() { return name; } public void setName(String name) { this .name = name; } public Man getMan() { return man; } public void setMan(Man man) { this .man = man; } public User copy(){ try { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject( this ); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); User user = (User) objectInputStream.readObject(); return user; } catch (Exception e) { e.printStackTrace(); } return null; } @Override public String toString() { return "User{" + "name='" + name + '\ '' + ", man=" + man + '}' ; } public static class Man implements Serializable { private String job; public String getJob() { return job; } public void setJob(String job) { this .job = job; } @Override public String toString() { return "Man{" + "job='" + job + '\ '' + '}' ; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | private static void ioDeepClone() { User user = new User(); user.setName( "rose" ); User.Man man = new User.Man(); man.setJob( "teacher" ); user.setMan(man); User userCopy = user.copy(); System.out.println(user.hashCode()); // 225534817 System.out.println(userCopy.hashCode()); // 122883338 System.out.println(user.getMan().hashCode()); // 1878246837 System.out.println(userCopy.getMan().hashCode()); // 666641942 user.getMan().setJob( "coder" ); System.out.println(user.getMan()); // Man{job='coder'} System.out.println(userCopy.getMan()); // Man{job='teacher'} } |
五、为什么使用clone方法需要实现java.lang.Cloneable接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /** * <为什么使用clone方法需要实现java.lang.Cloneable接口> * 下载JDK源码,进入hotspot/src/share/vm/prims/jvm.cpp文件中 * * // Check if class of obj supports the Cloneable interface. * // All arrays are considered to be cloneable (See JLS 20.1.5) * if (!klass->is_cloneable()) { * ResourceMark rm(THREAD); * THROW_MSG_0(vmSymbols::java_lang_CloneNotSupportedException(), klass->external_name()); * } * * Check if class of obj supports the Cloneable interface.检查指定的class是否实现java.lang.Cloneable接口(数组默认支持clone); * 如果 !klass->is_cloneable() 抛出CloneNotSupportedException; * * clone代码: * JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle)) * JVMWrapper("JVM_Clone"); * Handle obj(THREAD, JNIHandles::resolve_non_null(handle)); * const KlassHandle klass (THREAD, obj->klass()); * JvmtiVMObjectAllocEventCollector oam; */ |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
2019-04-24 SpringCloud---API网关服务---Spring Cloud Zuul