java集合复制_Java对象和集合的拷贝/克隆/复制

昨天同事遇到了一个奇怪的问题,他需要将一个JavaBean拷贝一份,然后对新创建的Bean进行操作。但是他对新的Bean操作后,会影响旧的Bean的值。当听到这个问题的时候,我第一反应就是他的拷贝方法有问题,只是将aBean的内容复制给了bBean,但是在内存中指向的是同一个地址。这里就引出了两个关键词,浅拷贝和深拷贝。

浅拷贝(浅克隆)

被复制对象的所有变量值都和原来的对象的值相同,但是复制后的对象的引用仍然指向原来的对象。简单来说,就是对A进行拷贝生成B,只是将A的值复制给了B,内存中指向的是同一地址,影响就是改变B的同时,A的值也会改变。

深拷贝(深克隆)

被复制对象的所有变量值都和原来的对象的值相同,除了变量的值改变,也会创建新的指向变量的地址。源对象A和复制后的B,虽然内容是一样的,但是各自指向的地址不同,所以改变相互不受影响。

那问题已经知道,Java的Bean对象要怎么进行深拷贝呢。

一、Java对象克隆

Java中对象的深克隆

①利用Object类的clone()方法。

②在派生类中重写基类的clone方法,并声明为public。

③在派生类的clone()方法中,调用super.clone()。

④在派生类中实现Cloneable接口。

这是一个Student的类,重写了clone()方法。

public class Student implements Cloneable {

private String name;

private int age;

public Student(String name, int age) {

super();

this.name = name;

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public Object clone() {

Object o = null;

try {

o = (Student)super.clone();

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

return o;

}

@Override

public String toString() {

return "Student [name=" + name + ", age=" + age + "]";

}

}

测试clone

public static void main(String[] args) {

Student s1=new Student("张三",18);

System.out.println("修改前s1值:" + s1.toString());

Student s2=(Student)s1.clone();

s2.setName("李四");

s2.setAge(20);

//修改学生2后,不影响学生1的值。

System.out.println("修改后s1值:" + s1.toString());

System.out.println("s2的值:" + s2.toString());

}

控制台输出的结果如下:

修改前s1值:Student [name=张三, age=18]

修改后s1值:Student [name=张三, age=18]

s2的值:Student [name=李四, age=20]

上面的例子对象中的属性是基本类型,但是如果包含非基本类型,结果怎样呢,上代码,对Student类进行修改,加入Course类。

Student类

public class Student implements Cloneable {

private String name;

private int age;

private Course course;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public Course getCourse() {

return course;

}

public void setCourse(Course course) {

this.course = course;

}

public Student(String name, int age, Course course) {

super();

this.name = name;

this.age = age;

this.course = course;

}

public Student() {

}

public Object clone() {

Object o = null;

try {

o = (Student)super.clone();

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

return o;

}

@Override

public String toString() {

return "Student [name=" + name + ", age=" + age + ", course=" + course + "]";

}

}

Course类

public class Course {

private String name;

private int value;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getValue() {

return value;

}

public void setValue(int value) {

this.value = value;

}

public Course(String name, int value) {

super();

this.name = name;

this.value = value;

}

public Course() {

}

@Override

public String toString() {

return "Course [name=" + name + ", value=" + value + "]";

}

}

测试克隆

public static void main(String[] args) {

Student s1 = new Student();

s1.setName("张三");

s1.setAge(24);

Course c = new Course();

c.setName("语文");

c.setValue(80);

s1.setCourse(c);

System.out.println("修改前s1值:" + s1.toString());

Student s2 = (Student)s1.clone();

s2.setName("李四");

s2.setAge(20);

Course c2 = s2.getCourse();

c2.setName("数学");

c2.setValue(90);

//修改学生2的Course后,影响学生1的Course。

System.out.println("修改后s1值:" + s1.toString());

System.out.println("s2的值:" + s2.toString());

}

控制台输出结果

修改前s1值:Student [name=张三, age=24, course=Course [name=语文, value=80]]

修改后s1值:Student [name=张三, age=24, course=Course [name=数学, value=90]]

s2的值:Student [name=李四, age=20, course=Course [name=数学, value=90]]

上面的例子说明调用clone方法,拷贝原始对象中的内容,对于基本数据类型,这样的操作是没有问题的,但是对于非基本类型,它们保存的仅仅是对象的引用。

为了解决上面的问题,我们需要使用深度克隆方案。修改之后的Student类和Course类如下

Student类

public class Student implements Cloneable {

private String name;

private int age;

private Course course;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public Course getCourse() {

return course;

}

public void setCourse(Course course) {

this.course = course;

}

public Student(String name, int age, Course course) {

super();

this.name = name;

this.age = age;

this.course = course;

}

public Student() {

}

public Student clone() {

Student s = null;

try {

s = (Student)super.clone();

s.course = course.clone();

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

return s;

}

@Override

public String toString() {

return "Student [name=" + name + ", age=" + age + ", course=" + course + "]";

}

}

Course类

public class Course implements Cloneable{

private String name;

private int value;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getValue() {

return value;

}

public void setValue(int value) {

this.value = value;

}

public Course(String name, int value) {

super();

this.name = name;

this.value = value;

}

public Course() {

}

public Course clone() {

Course c = null;

try {

c = (Course)super.clone();

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

return c;

}

@Override

public String toString() {

return "Course [name=" + name + ", value=" + value + "]";

}

}

测试方法使用之前的方法,下面的运行后的结果。

修改前s1值:Student [name=张三, age=24, course=Course [name=语文, value=80]]

修改后s1值:Student [name=张三, age=24, course=Course [name=语文, value=80]]

s2的值:Student [name=李四, age=20, course=Course [name=数学, value=90]]

根据结果可知,通过深度克隆后,clone后的对象非基本类的变量修改,不会对原对象造成影响。

对于集合的Clone操作也一样,集中的属性如果是基本数据类型的话,循环赋值,或者使用addAll()方法都不会对原集合造成影响。若集合中存放了非基本数据类型的话,如上述中的Student对象,就必须对Student对象添加重写clone()方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值