深拷贝和浅拷贝

2020-09-02  本文已影响0人  竖起大拇指

我们这里先定义两个类:Student和Major,分别表示学生和所学的专用,二者是包含关系:

   class Major{
      var majorName:String?=null
      var majorId:Long=0
}

class Student{
    var name:String?=null
    var age:Int=0
    var major:Major?=null
}

对象赋值

赋值时日常编程过程中最常见的操作,最简单的比如:

  var student=Student()
   var student1=student

严格来说,这种不算对象拷贝,因为拷贝的仅仅只是引用关系,并没有生成新的实际对象。

浅拷贝

浅拷贝属于对象克隆方式的一种,重要的特性体现在浅字上。主要实现逻辑是 基本类型的字段会复制一份,而引用类型的字段拷贝的仅仅是引用地址,而且该引用地址指向的实际对象空间其实只有一份。

深拷贝

深拷贝相较于浅拷贝,除了值类型字段会复制一份,引用类型字段所指向的对象,会在内存中也创建一个副本。

我们来看看具体的代码实现:

浅拷贝代码实现

open class Student :Cloneable{

    var name:String?=null
    var age:Int=0
    var major:Major?=null


    public override fun clone(): Student {
        return super.clone() as Student
    }

    override fun toString(): String {
        return "Student(name=$name, age=$age, major=$major)"
    }

}

测试代码:

companion object{
        @JvmStatic
        fun main(args: Array<String>) {
            var major=Major()
            major.majorId=6666
            major.majorName="计算机科学与技术"

            var student=Student()
            student.age=20
            student.name="毛大哥"
            student.major=major


            var cloneStudent=student.clone()

            println(cloneStudent==student)
            println("cloneStudent:${cloneStudent}")
            println("student:${student}")

            student.age=22
            major.majorName="计算机应用技术"
            major.majorId=3333

            println("------------after-----------")
            println("cloneStudent:${cloneStudent}")
            println("student:${student}")

        }
    }

运行得到如下结果:

false
cloneStudent:Student(name=毛大哥, age=20, major=com.ble.kotlinscope.clone.Major@5e481248)
student:Student(name=毛大哥, age=20, major=com.ble.kotlinscope.clone.Major@5e481248)
------------after-----------
cloneStudent:Student(name=毛大哥, age=20, major=com.ble.kotlinscope.clone.Major@5e481248)
student:Student(name=毛大哥, age=22, major=com.ble.kotlinscope.clone.Major@5e481248)

从结果可以看出:

深拷贝代码实现

虽然clone方法可以完成对象的拷贝工作,但是注意:clone()方法默认是浅拷贝行为,若想实现深拷贝需要覆写clone方法实现对象的深度遍历式拷贝。
对于上面的例子,如果想实现深拷贝,首先需要对更深一层的引用类Major做改造,让其也实现Cloneable接口并重写clone方法:

class Major :Cloneable {

    var majorName:String?=null

    var majorId:Int=0

    public open override fun clone(): Major {
        return super.clone() as Major
    }

    override fun toString(): String {
        return "Major(majorName=$majorName, majorId=$majorId)"
    }
}

其次我们还需要在顶层的调用类中重写clone方法,来调用引用类型字段的clone方法来实现深度拷贝。

open class Student :Cloneable{

    var name:String?=null
    var age:Int=0
    var major:Major?=null


    public override fun clone(): Student {
        var student=super.clone() as Student
        student.major=major?.clone()
        return student
    }

    override fun toString(): String {
        return "Student(name=$name, age=$age, major=$major)"
    }

}

上面测试用例不变,运行结果如下:

false
student:Student(name=毛大哥, age=20, major=Major(majorName=计算机科学与技术, majorId=6666))
cloneStudent:Student(name=毛大哥, age=20, major=Major(majorName=计算机科学与技术, majorId=6666))
------------after-----------
student:Student(name=毛大哥, age=22, major=Major(majorName=计算机应用技术, majorId=3333))
cloneStudent:Student(name=毛大哥, age=20, major=Major(majorName=计算机科学与技术, majorId=6666))

很明显,这时候student和cloneStudent两个对象完全独立,不受互相的干扰.

上一篇 下一篇

猜你喜欢

热点阅读