添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

先上通过 clone 深拷贝的使用步骤:

  1. model 先实现 Cloneable, 重写 clone 方法.
  2. model 调用 clone 就会生成一个 全新的对象.
  3. new 一个新数组 copyList, 遍历 原始数组 oriList, 一个一个添加到 copyList 即可.

talk is cheap, show me the code:

class MainKotlin {
    @Test
    fun test0() {
        val oriList = ArrayList<Model>()
        val model0 = Model(0, "name0")
        val model1 = Model(1, "name1")
        val model2 = Model(2, "name2")
        oriList.add(model0)
        oriList.add(model1)
        oriList.add(model2)
        val copyList = ArrayList<Model>()
        oriList.forEach {
            copyList.add(it.clone())
        println("list = $oriList")
        println("copyList = $copyList")
        println("======== change name ========")
        model0.name = "name0 changed"
        println("list = $oriList")
        println("copyList = $copyList")
    class Model(): Cloneable {
        var id: Int? = null
        var name: String? = null
        constructor(id: Int, name: String) : this() {
            this.id = id
            this.name = name
        // 添加 try catch, 防止奇怪的异常
        public override fun clone(): Model {
            return try {
                return super.clone() as? Model ?: Model()
            } catch (e: CloneNotSupportedException) {
                Model()
        override fun toString(): String {
            return "Model(id=$id, name=$name)"

输出结果: 

        可以看到 model0 更改 name 时, list 随之改变, copyList 没有改变, 成功~

        今天在做单例的时候, 被数据的一些状态整懵了, 虽然想到了可以通过深拷贝解决问题, 但竟然直接使用了 newList.addAll(oldList) ... 结果又排查问题查了半天...才想到 list 中的 model 也是要完全 new 出来才行, model 里面那么多属性, 一个一个赋值太不优雅啦, 在网上查了下可以通过:

  1. clone 实现
  2. 实现序列化, 通过反序列化 new 出来对象
  3. 转成 json 字符串, 再转成对象(解析最好在子线程)

序列化深拷贝实现见 后续补充.

        java的一个类,如果要使用 Cloneable 实现拷贝功能, 需要先实现这个接口, 然后重写Object的clone方法. 对于类中的引用类型的属性, 需要在clone方法中实现深拷贝, 否则就是浅拷贝.

        属性中有引用对象的话, 引用对象也要实现 Cloneable, 然后这个引用对象也要调用 clone 方法才行...有点麻烦, 得封装一下才好用...后续带封装...

后续待优化: 

        可以把 集合 的深拷贝封装一个函数, 这样调用起来比较方便, 待执行任务...

序列化实现, 有两种, Serializable 和 Parcelable

Serializable 存在文件读写的过程, Parcelable 是在内存中操作, 建议使用 Parcelabel.

1. Serializable 实现

当前需要类实现 Serializable 接口, 并且如果成员变量有引用类型, 此引用类型也需要实现 Serializable 接口, 这样深拷贝才能成功

java 代码

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class DeepCopyUtil {
    public static Object deepClone(Serializable obj) {
        Object anotherObj = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        try {
            oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            byte[] bytes = baos.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bais);
            anotherObj = ois.readObject();
        } catch (Exception ex) {
        } finally {
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException localIOException3) {
                    Logger.e("deepClone error:"+localIOException3.getMessage());
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException localIOException4) {
        return anotherObj;

kotlin 代码

fun <T : Serializable> T.deepCopy(obj: T?): T? {
    if (obj == null) return null
    val baos = ByteArrayOutputStream()
    val oos  = ObjectOutputStream(baos)
    oos.writeObject(obj)
    oos.close()
    val bais = ByteArrayInputStream(baos.toByteArray())
    val ois  = ObjectInputStream(bais)
    @Suppress("unchecked_cast")
    return ois.readObject() as T

2. Parcelable 实现

注意 parcelabel 需要在 android 环境中测试, 在 java 中会报异常 java.lang.RuntimeException: Stub!...

 参考 https://farhanpatel.dev/index.php/2020/06/14/deep-clones-with-android-parcelable/

fun <T : Parcelable> deepClone(objectToClone: T): T? {
        var parcel: Parcel? = null
        return try {
            parcel = Parcel.obtain()
            parcel.writeParcelable(objectToClone, 0)
            parcel.setDataPosition(0)
            parcel.readParcelable(objectToClone::class.java.classLoader)
        } finally {
            //it is important to recyle parcel and free up resources once done.
            parcel?.recycle()
				
Java的浅拷贝(Shallow Copy)、深拷贝(Deep Copy)。 浅拷贝(Shallow Copy): 1、对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。 2、对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的.
import java.util.* import kotlin.collections.ArrayList import kotlin.reflect.full.createInstance import kotlin.reflect.full.memberProperties import kotlin.reflect.jvm.javaField * @Description: 用来复制元素的工具类 * @Author: dk * @Date: 2021/6/28 12:05 PM
为了使查询出来的数据不受到污染,经常会将数据拷贝到一个可以随意使用的集合中,而在期间的就需要进行copy操作。 以前的我使用循环遍历(for循环)然后存到另一个集合中,但是这样会有很多冗余代码,且for循环影响程序执行效率(数据很多的情况下) 为了简化代码,我找到了Collection中的copy方法,该方法会将原集合数据(src)copy到目的集合(dest) Collections.co...
kotlin Cloneable 的奇怪行为 在使用 kotlinCloneable 时,发现它表示得很奇怪。如果类直接继承了 Cloneable ,那么它的表现很正常 和 java使用差不多,如下: package demo interface Foo { fun createClone(): Foo fun doSomething() class Bar: F...
深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型 浅拷贝(Shadow Clone) 浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。 深拷贝(Deep Clone深拷贝会另外创建一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。 深拷贝实现方式(4种) 序列化然后反序列化对象后,得到一个新对象 手动创建新对象,遇到对象和数组时,手动创建新对象并将其赋值,手动创建新数组并遍历赋值 重写 kotlin data class c
fun main(args: Array<String>) { val list = mutableListOf("one", "two") val c1 = Container(list) val c2 = c1.copy() list += "o.
Android Studio中将Kotlin转换为Java,可以使用以下步骤: 1. 打开Kotlin文件,右键单击文件名并选择“Convert Kotlin File to Java File”选项。 2. 在弹出的对话框中,选择要转换的文件和目标文件夹。 3. 点击“OK”按钮开始转换过程。 4. 转换完成后,将在目标文件夹中生成Java文件。 需要注意的是,转换过程中可能会出现一些语法错误或类型转换问题,需要手动进行修复。此外,转换后的Java代码可能不如原始的Kotlin代码简洁和易读。