JavaKotlin中的深复制与浅复制

1、传引证与复制的差异

请看如下代码

Students1=newStudent();
Students2;
s2=s1;

以上的代码便是一个传递引证的比方,s1与s2是同一处引证,它们指向的是内存地址中的同一处目标,而复制应该是新创建一个目标。

2、深复制与浅复制的差异

这两者的本质便是引证数据类型的复制问题,也便是复制层次。

基本数据类型没有差异,但是两个目标中假如有特点是引证数据类型,浅复制不会从头创建一个新的目标,这两个目标的这个特点它们指向的是同一处引证,修正其中一个目标的这个特点会影响到另一个目标;而深复制不会,深复制会从头创建一个目标,将这个目标赋值给复制目标目标的那个特点身上。

3、Java中的浅复制以及深复制的完成

在Java中,所有类的基类Object类有一个clone()办法,它默许能够完成一个浅复制,如下示例

publicclassCopy{
publicstaticvoidmain(String[]args)throwsCloneNotSupportedException{
Students1=newStudent("AB",18);
Students2=(Student)s1.clone();
s2.setAge(20);
System.out.println(s1);
System.out.println(s2);
}
}
classStudentimplementsCloneable{
@Override
protectedObjectclone()throwsCloneNotSupportedException{
returnsuper.clone();
}
privateStringname;
privateIntegerage;
@Override
publicStringtoString(){
return"Student{"+
"name='"+name+'''+
",age="+age+
'}';
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicIntegergetAge(){
returnage;
}
publicvoidsetAge(Integerage){
this.age=age;
}
publicStudent(Stringname,Integerage){
this.name=name;
this.age=age;
}
publicStudent(){
}
}

输出如下

Student{name='AB',age=18}
Student{name='AB',age=20}

咱们发现改动s2目标的age特点并没有影响到s1目标,所以这s2与s1的确不是同一个目标,咱们完成了一个目标的复制。但为什么说这个默许完成的clone()办法是一个浅复制呢?咱们做如下改造

publicclassCopy{
publicstaticvoidmain(String[]args)throwsCloneNotSupportedException{
Students1=newStudent("AB",18,"math");
Students2=(Student)s1.clone();
s2.setAge(20);
s2.getSubject().setName("english");
System.out.println(s1);
System.out.println(s2);
}
}
classStudentimplementsCloneable{

privateStringname;
privateIntegerage;
privateSubjectsubject;
@Override
protectedObjectclone()throwsCloneNotSupportedException{
returnsuper.clone();
}

@Override
publicStringtoString(){
return"Student{"+
"name='"+name+'''+
",age="+age+
",subject="+subject+
'}';
}
publicSubjectgetSubject(){
returnsubject;
}
publicvoidsetSubject(Subjectsubject){
this.subject=subject;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicIntegergetAge(){
returnage;
}
publicvoidsetAge(Integerage){
this.age=age;
}
publicStudent(Stringname,Integerage,Stringsubject){
this.name=name;
this.age=age;
this.subject=newSubject(subject);
}
publicStudent(){
}
}
classSubject{
privateStringname;
@Override
publicStringtoString(){
return"Subject{"+
"name='"+name+'''+
'}';
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicSubject(Stringname){
this.name=name;
}
}

输出如下

Student{name='AB',age=18,subject=Subject{name='english'}}
Student{name='AB',age=20,subject=Subject{name='english'}}

咱们会发现咱们向Student类中增加一个引证数据类型Subject类型的特点,咱们仍是使用默许的clone()办法完成,当咱们改动s2的subject特点的name特点时会影响s1目标,也便是说s1目标中的subject特点和s1目标中的subject特点是同一个引证,这也便是浅复制。

当然要解释一下,Student类中的有参结构中第三个参数传入String类型而不传入Subject类型是故意为之,许多时候有这种需求场景,假如直接传入Subject类型的参数仍是能够成功复制的。

那Java中咱们怎样去做一下深复制呢,比较简略的办法便是咱们自己去重写一下这个clone办法就好了,如下

@Override
protectedObjectclone()throwsCloneNotSupportedException{
Studentclone=(Student)super.clone();
clone.setSubject(newSubject(this.subject.getName()));
returnclone;
}

改完后输出如下

Student{name='AB',age=18,subject=Subject{name='math'}}
Student{name='AB',age=20,subject=Subject{name='english'}}

咱们发现简略修正后就完成了深复制,当然这个深复制也是相对而言的,比方Subject类中也有了一个引证数据类型的特点,那就要复制两层了,其实完成的办法许多,用这种简略的办法也能够,不在过多介绍。

4、Kotlin中的浅复制与深复制的完成

Kotlin中有数据类(data class),数据类中自带一个copy()函数,这个函数跟Java中的clone()办法是相同的,也是默许完成一个浅复制。 仍是Java中的比方,简略演示一下。

funmain(){
vals1=Student("Jack",18)
vals2=s1.copy()
s2.age=20

println(s1)
println(s2)
}
dataclassStudent(valname:String,varage:Int)

输出如下

Student(name=Jack,age=18)
Student(name=Jack,age=20)

那咱们发现copy()函数的确跟Java中的clone()办法很像,并且它也是完成了一个浅复制,这里就不作验证了。

多提一句,咱们其实能够看到Kotlin中的代码量明显变少,一方面Kotlin中的这个数据类默许完成了toString()、equals()、hashCoe()等办法,为了简化一些没有事务逻辑只负责封装数据的类的写法,削减重复代码量;另一方面,Kotlin的语法糖真的出了名的多,不仅是数据类,它许多的写法都很简洁,在Java的一些基础上做了许多改善。

接下来咱们看一下在Kotlin中怎样简略写一下深复制,跟Java相同,在数据类中重写一下copy()函数就能够了(其实这里严格来说也不是重写,仅仅咱们写一个copy函数它就会调用咱们自己写的copy函数)。如下

funmain(){
vals1=Student("Jack",18,"math")
vals2=s1.copy()
s2.age=20
s2.subject.name="english"
println(s1)
println(s2)
}
dataclassStudent(valname:String,varage:Int,valsubject:Subject){
constructor(name:String,age:Int,subject:String):this(name,age,Subject(subject))
funcopy()=Student(this.name,this.age,Subject(this.subject.name))
}
dataclassSubject(varname:String)

输出如下

Student(name=Jack,age=18,subject=Subject(name=math))
Student(name=Jack,age=20,subject=Subject(name=english))

这样咱们就用Kotlin简略完成了一下深复制。

5、简略总结

  • 浅复制与深复制的本质问题便是复制的层次问题,浅复制相对不会将目标的引证数据类型的特点复制一份
  • Java中使用clone()办法默许完成浅复制,能够经过重写简略完成一个深复制
  • Kotlin中数据类默许的copy()函数默许完成浅复制,能够经过重写简略完成一个深复制

关于深复制与浅复制的内容就简略聊到这,还有许多完成深复制的办法,更加地合理和高级,感兴趣能够去收集学习。

文章若由错误之处,欢迎纠正!