💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
定义: clone顾名思义就是克隆,即复制一个相等的对象,但是不同的引用地址; clone方法是被native修饰的,简单的讲就是被Native修饰的方法在被调用时指向的是一个非java代码的具体实现,这个实现可能是其他语言或者操作系统; ### clone规则 1、 基本类型如果变量是基本类型,则拷贝其值,比如int、float等。 2、 对象如果变量是一个实例对象,则拷贝其地址引用,也就是说新对象和原来对象是共用实例变量的。 3、 String字符串若变量为String字符串,则拷贝其地址引用。但是在修改时,它会从字符串池中重新生成一个新的字符串,原有的对象保持不变 分类 * 浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝 * 深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容 ### clone的工作原理 java.lang.Object提供了默认的clone方法实现,它声明为protected和native。因此它的实现是取决于本地代码,因为它约定返回对象是通过调用super.clone\(\)方法,任何克隆的过程最终都将到达java.lang.Object 的clone\(\)方法,它首先检查这个相关的类是否实现了Cloneable接口,这个接口是一个标记接口,如果这个实例没有实现cloneable接口,那么就会抛出CloneNotSupported异常,这个异常是一个checked异常,也就是说他在克隆对象的时候总需要被处理。如果没有异常抛出,然后java.lang.Object的clone\(\)方法将创建一个拷贝返回给调用者。因为Object类的clone\(\)方法通过创建新对象来生成这个副本的,然后逐个域拷贝(field-by-filed),类似于赋值操作,这种操作对于原始类型(primitives)和不可变类型(immutable)来说是没问题的,但是如果你的类包含一些可变的数据结构如:ArrayList或数组就不合适了,这种情况原始对象和副本对象将指向相同的堆,你可以通过一种叫深度克隆的技术防止这种事情发生 ### 总结 * 克隆方法用于创建对象的拷贝,为了使用clone方法,类必须实现java.lang.Cloneable接口重写protected方法clone,如果没有实现Clonebale接口会抛出CloneNotSupportedException. * 在克隆java对象的时候不会调用构造器 * java提供一种叫浅拷贝(shallow copy)的默认方式实现clone,创建好对象的副本后然后通过赋值拷贝内容,意味着如果你的类包含可变对象,那么原始对象和克隆都将指向相同的内部对象,这是很危险的,因为发生在可变的字段上任何改变将反应到原始对象和副本对象上。为了避免这种情况,重写clone\(\)方法。 * 按照约定,实例的克隆应该通过调用super.clone\(\)获取,这样有助克隆对象的不变性建如:clone!=original和clone.getClass\(\)==original.getClass\(\),尽管这些不是必须的 * clone机制非常高效,比如clone一个包含100个元素的int\[\]数组,clone方法比静态copy快近2倍; ### 通过序列化实现深拷贝 也可以通过序列化来实现深拷贝。序列化是干什么的?它将整个对象图写入到一个持久化存储文件中并且当需要的时候把它读取回来, 这意味着当你需要把它读取回来时你需要整个对象图的一个拷贝。这就是当你深拷贝一个对象时真正需要的东西。 请注意,当你通过序列化进行深拷贝时,必须确保对象图中所有类都是可序列化的; 序列化这种方式有其自身的限制和问题:无法序列化transient变量, 使用这种方法将无法拷贝transient变量