java字符串赋值是浅拷贝,关于Java的浅拷贝和深拷贝

浅拷贝和深拷贝是什么?

浅拷贝和深拷贝都是针对已经存在了的对象的操作,在java中,基本数据类型有八种,和引用数据类型。在程序中,一般用 = 来做赋值的操作,对于基本数据类型,实际上是拷贝它的值,而对于引用数据类型,则是拷贝的它的引用地址,举例如下:

@Test

public void m2() {

int i = 1;

int j = i;

System.out.println(j);

Student stu1 = new Student("zhangsan", 12);

System.out.println(stu1);

Student stu2 = stu1;

stu2.setAge(20);

System.out.println(stu1);

System.out.println(stu2);

}

运行结果:

1

Student{name='zhangsan', age=12, active=null}

Student{name='zhangsan', age=20, active=null}

Student{name='zhangsan', age=20, active=null}

从运行的结果,发现一个问题,int类型的值不用多说,而在引用类型中,明明修改的是stu2的age,为什么stu1的age也发生了变化,这里就涉及到了值传递和引用传递的问题了,ok,后面介绍。

Java中的clone()方法

说到拷贝操作,那java必定提供了API来供我们使用,那就是Object类中的clone()方法了(它是一个native方法),既然是超类中的protected方法,那么子类中就有必要重写一下,所有使用调用clone()来拷贝的时候,其对象必须要实现标识接口Cloneable,否则就会抛出CloneNotSupportedException这个异常。

浅拷贝

首先创建一个Studen类,并实现Cloneable接口,重写clone方法。

public class Student implements Cloneable {

private String name;

private int age;

private Active active;

public Object clone() throws CloneNotSupportedException {

return super.clone();

}

// 省略get、set方法

}

Active类的实现:

public class Active implements Cloneable {

private String name;

public Object clone() throws CloneNotSupportedException {

return super.clone();

}

public Active(String name) {

this.name = name;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

}

测试用例:用clone方法,复制新new出来的student1,得到student2,再做各种比较。

@Test

public void m1() throws Exception {

Student student1 = new Student();

student1.setAge(10);

student1.setName("zhangsan");

student1.setActive(new Active("pingpang"));

// 原始对象的hashcode

System.out.println(student1.hashCode());

// 克隆出来的对象

Student student2 = (Student) student1.clone();

// 克隆出来的对象的hashcode

System.out.println(student2.hashCode());

// 两个对象是否一样

System.out.println(student1 == student2);

// 两个对象比较

System.out.println(student1);

System.out.println(student2);

// 两个对象各自的引用比较

System.out.println(student1.getActive());

System.out.println(student2.getActive());

}

运行结果:

697960108

943010986

false

Student@299a06ac

Student@383534aa

Active@6bc168e5

Active@6bc168e5

可以得出关于浅拷贝的几点结论:

clone()方法,会创建一个新的对象。

浅拷贝基本数据类型是拷贝值。

拷贝引用数据类型如:Active ,则拷贝的是它的引用地址。

深拷贝

Student类,在克隆此类对象的时候,将此对象中的引用属性也克隆一份,只有clone方法不同:

public class Student implements Cloneable {

private String name;

private int age;

private Active active;

public Object clone() throws CloneNotSupportedException {

Student student = (Student) super.clone();

student.active = (Active) this.active.clone();

return student;

}

// get、set方法省略

}

Active类,实现Cloneable接口,并重写了clone方法:

public class Active implements Cloneable {

private String name;

public Object clone() throws CloneNotSupportedException {

return super.clone();

}

public Active(String name) {

this.name = name;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

}

测试用例:

@Test

public void m1() throws Exception {

Student student1 = new Student();

student1.setAge(10);

student1.setName("zhangsan");

student1.setActive(new Active("pingpang"));

// 原始对象的hashcode

System.out.println(student1.hashCode());

// 克隆出来的对象

Student student2 = (Student) student1.clone();

// 克隆出来的对象的hashcode

System.out.println(student2.hashCode());

// 两个对象是否一样

System.out.println(student1 == student2);

// 两个对象比较

System.out.println(student1);

System.out.println(student2);

// 两个对象各自的引用比较

System.out.println(student1.getActive());

System.out.println(student2.getActive());

}

测试结果中显示不同student对象中的active对象也不同了:

697960108

943010986

false

com.nmys.story.interview.copy_interview.Student@299a06ac

com.nmys.story.interview.copy_interview.Student@383534aa

com.nmys.story.interview.copy_interview.Active@6bc168e5

com.nmys.story.interview.copy_interview.Active@7b3300e5

可以得出深拷贝的几点结论:

深拷贝是完全创建一个新的对象

深拷贝也会将原始对象中的引用对象重新复制一份

总结

一定要实现Cloneable接口。

重写clone()方法,注意:默认是浅拷贝,这里需要将引用类型进行深拷贝处。

特殊:String类虽然是引用类型,但是是final类,同时也有字符串常量池的存在,不必进行处理。

深拷贝可以通过上面所说的clone方法实现,还可以通过序列化来实现。

当时写测试用例的时候,我这里用了lombok的注解@Data,为的就是不用手写get、set方法了,但测试的时候,发现clone出来的对象的hashcode是一样的,原因是lombok在为我们生成get、set的同时,toString、hashCode、equals等方法都替我们重写了,导致clone出来的类虽然 == 是 false ,但是hashCode却一样,建议还是手动写比较好。

最后再总结下,假设,A 类中引用了 B 类,B 类中引用了 C 类,对象分别对应 a,b,c,浅拷贝 a 的结果 a1,b,c。深拷贝 a 的结果 a1,b1,c1。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值