1、对象拷贝:
对象拷贝,主要牵扯的是内存的问题,如User user =new User();拷贝(赋值)之后的新对象,和之前的老对象是否存在共用在堆上的内存问题。
tips:1、new出来的对象在堆上存在,主要就是判别这块。
2、堆地址不同,深拷贝,原对象和新对象互不影响。反之,只要有部分的共用内存,就是浅拷贝。
2、基本思路:
1、直接new一个新的对象,调用get、set方法。new了块新的内存,深拷贝,内存不共用。
后面不再赘述。
User user = new User(a,b,c);
User user2 = new User();
user2.setA(user.getA());
2、实现Cloneable接口的浅拷贝
实现Cloneable接口,并重写clone方法,实现对象的拷贝(其实也不完全是浅拷贝,当拷贝的内,内部没有自定义的类对象时也是深拷贝的。这块说是浅拷贝的,是因为有类变量)
3、实现Serializable接口的深拷贝
序列化是把对象的副本拷贝到流里面,再把流里面的对象反序列化,重而实现一个和原对象不同堆地址的深拷贝。注意的是,借用此方式实现深拷贝的类,下面的子类也必须实现Serializable接口。不然无法序列化,报错
此块和Cloneable接口的不一样,(实现cloneable接口的此类,下面的类对象类,可以/可以不 实现cloneable接口)
4、遇自定义类皆实现Cloneable接口的深拷贝(前面2、说的是浅拷贝)
3、代码实现
1、new对象,直接set、get方法 省略
2、实现Cloneable接口的浅拷贝
class Door implements Cloneable{
public int doorNum;
public String name;
public Door(int doorNum, String name) {
this.doorNum = doorNum;
this.name = name;
}
public Door() {
}
}
class Car implements Cloneable{
int whell;
Door door;//成员类 没有实现Cloneable接口
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Car(int whell, Door door) {
this.whell = whell;
this.door = door;
}
}
MainMethod:
//2、实现Cloneable接口的
Car car = new Car(4,new Door(2,"A"));
Car car1 =(Car) car.clone();//这块,必须进行一个类型的强制转换
System.out.println("car:"+car.door.doorNum+car.door.name+car.whell);
System.out.println("car1:"+car1.door.doorNum+car1.door.name+car1.whell);
//此时输出结果是一样的,car 和car1 内容一致
car.whell=5;//实现了cloneable接口的类
car.door.name = "B";//成员对象 没有实现cloneable接口
System.out.println("car:"+car.door.doorNum+car.door.name+car.whell);
System.out.println("car1:"+car1.door.doorNum+car1.door.name+car1.whell);//证实了是浅拷贝 只对当前类中的进行了深拷贝,对象类成员是浅拷贝
//修改了car的whell 和door.name 外部Car类的其他成员(whell)是不一致的,证实了只有当前类中的非成员对象 是深度拷贝
//door由于是引用类型 没有实现clone接口及方法 所以修改了door.name后 car和car1的都变了
3、实现Serializable接口的深拷贝
class Teacher implements Serializable{
private static final long seriaVersionUID = -8099797912131114222L;
public int age;
public String name;
public Teacher(int age, String name) {
this.age = age;
this.name = name;
}
public Teacher() {}
//get set方法省略
public void setName(String name) {
this.name = name;
}
}
class Student implements Serializable{
private static final long seriaVersionUID = -8099797912131114211L;
public int age;
public String name;
public Teacher teacher;
public Student(int age, String name, Teacher teacher) {
this.age = age;
this.name = name;
this.teacher = teacher;
}
//get set方法省略
public Object DeepCopy() throws Exception{//使用序列化和反序列化 实现克隆的逻辑
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}
MainMethod
//3、实现Seriliazble 接口的 这个实现方式,是完全的深度拷贝,即外部类和成员类对象,都实现了seriliable接口,那么外部类和类的其他类变量 都是new了份新的 内存分离
Teacher teacher = new Teacher(40,"TeacherA");
Student student=new Student(20,"StuA",teacher);
Student student1 = (Student) student.DeepCopy();
System.out.println("stu.age: "+student.getAge()+" stu.name: "+student.getName()+" stu.teacher: "+student.getTeacher().getName()+student.getTeacher().getAge());
System.out.println("stu1.age: "+student1.getAge()+" stu1.name: "+student1.getName()+" stu1.teacher: "+student1.getTeacher().getName()+student1.getTeacher().getAge());
System.out.println();
student.getTeacher().setName("TeacherB");
student.getTeacher().setAge(45);
student.setAge(90);
System.out.println("stu.age: "+student.getAge()+"stu.name: "+student.getName()+"stu.teacher: "+student.getTeacher().getName()+student.getTeacher().getAge());
System.out.println("stu1.age: "+student1.getAge()+"stu1.name: "+student1.getName()+"stu1.teacher: "+student1.getTeacher().getName()+student1.getTeacher().getAge());
4、遇自定义类皆实现Cloneable接口的深拷贝(前面2、说的是浅拷贝)
class User implements Cloneable {
public String name;
public Account account;
@Override
protected User clone() {
try {
User user = (User) super.clone();//当前类实现了cloneable接口 ,重写clone方法
user.account = account.clone();//成员对象也实现了cloneable接口,重写了clone方法,所以整体上是深拷贝
return user;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
class Account implements Cloneable {
public int id;
public String name;
public double count;
@Override
protected Account clone() {
try {
return (Account) super.clone();//类User的类变量 也实现cloneable接口及方法 最后才是深拷贝
// 要是此类下还有public ClassA class;这样的类变量,那么这样的类也得实现cloneable接口 依次下去的都要实现 最后才能实现整体的深拷贝
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
MainMethod
//4、Cloneable实现的深拷贝
Account account=new Account();
account.id=1001;
account.name="张三的账户";
account.count=10000;
User user=new User();
user.account=account;
user.name="张三";
//执行赋值操作
User copyUser=user.clone();
System.out.println("原数据:"+user);
System.out.println("copy数据:"+copyUser);
System.out.println("\n修改后:\n");
//更改原数据
user.name="李四";
user.account.name="李四的账户";
System.out.println("原数据:"+user);
System.out.println("原数据的account对象:"+user.account);
System.out.println("copy数据:"+copyUser);
System.out.println("copy数据的account对象:"+copyUser.account);
总结:对象克隆的四种方式:
1、new新对象,直接调用get set,深拷贝,内存分离。
2、实现Cloneable接口的浅拷贝(之下有自定义类但没实现Cloneable接口及方法)
3、实现Serializable接口的深拷贝(下面所有类都必须实现Serializable接口)
4、实现Cloneable接口的深拷贝(类及之下有自定义类都得实现Cloneable接口及方法)
实现Serializable接口的最方便,直接new对象的最好想,Cloneable的,类的嵌套少还可以,不然实现很多clone挺麻烦的,不太建议用。
参考:https://blog.csdn.net/u010838555/article/details/102690626