克隆类型
在Java语言中,数据类型分为值类型(基本数据类型)和引用类型,值类型包括int、double、byte、boolean、char等简单数据类型,引用类型包括类、接口、数组等复杂类型。浅克隆和深克隆的主要区别在于潜克隆复制的时候如果是值类型则直接克隆,而如果是引用类型则不会克隆对象引用的对象,而只是简单地复制这个引用。也就是说如果修改克隆后的对象中的引用类型数据,原对象中也会更改,因为都是指向同一个内存。而深克隆则都会克隆。
浅克隆
被复制的类需要实现Clonenable接口, 该接口为标记接口(不含任何方法)
覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象。
将得到的复制对象返回
public class Student implements Cloneable{
private String name;
private int age;
private String addr;
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 String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
public Student(String name, int age, String addr) {
super();
this.name = name;
this.age = age;
this.addr = addr;
}
public Student() {
super();
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", addr=" + addr
+ "]";
}
@Override
protected Object clone() throws CloneNotSupportedException {
Student stu = null;
try{
stu = (Student)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
深克隆
自定义一个集合进行简单深克隆
ArrayList<Object> list = new ArrayList<>();
list.add("hello1");
list.add("hello2");
list.add("hello3");
Object clone = list.clone();
System.out.println(clone);
System.out.println(list);
//自己定义的数据类型 怎么克隆 备份 实现cloneable接口 重写方法
Student zs = new Student("张三",20, "上海");
Student zs2 = (Student) zs.clone();
System.out.println(zs);
System.out.println(zs2);
System.out.println(zs==zs2);//表示两个对象 不是同一个地址 false
System.out.println(zs.equals(zs2));//equals不重写的情况 比的还是地址 flase
System.out.println(zs.getAge()==zs2.getAge()); //true
System.out.println(zs.getAddr()==zs2.getAddr());//true
//两个属性的地址是一样的 说明不是完整的复制 -->浅克隆
深克隆
被复制的类需要实现Clonenable接口, 该接口为标记接口(不含任何方法)
覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象。
. 将得到的复制对象返回,(深克隆做法)如果对象中有引用对象那么对引用对象再克隆一次
class Student implements Cloneable{
private int number;
private ArrayList<String> image = new ArrayList<String>();
public int getNumber() {
return number;
}
public int getImage() {
return image;
}
public void setNumber(int number) {
this.number = number;
}
public void setImage(String url) {
this.image.add(url);
}
@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone();
//引用对象再次克隆
stu.image=this.image.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
}
当然这种深克隆方式有缺陷,如果引用对象有很多,或者说引用套引用很多重,比如image是个对象,对象里面又有引用对象,那么太麻烦了
解决多层克隆问题
用序列化的方式来实现对象的深克隆,其实如果你懂序列化的话就很容易理解了,就是把前面clone方法中的简单复制序列化后再返回。具体步骤就是先把对象序列化,转换为二进制码,然后再反序列化成对象,最后赋值。从而实现克隆
public class Student implements Cloneable,Serializable{//自定义类克隆实现接口
private String name;
private int age;
private String addr;
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 String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
public Student(String name, int age, String addr) {
super();
this.name = name;
this.age = age;
this.addr = addr;
}
public Student() {
super();
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", addr=" + addr
+ "]";
}
//第一种方式深克隆
@SuppressWarnings("resource")
@Override
protected Object clone() throws CloneNotSupportedException {
//深克隆 需要重写clone方法
//简单的说 复制就是读数据+写数据
//从this表示当前对象 读数据 然后生成新对象返回
//对象的读写 字节流
try {
//序列化 写
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\stu"));
oos.writeObject(this);//把当前对象 序列化(存一份)
oos.flush();
oos.close();
//反序列化 读
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\stu"));
Object object = ois.readObject();
return object;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.clone();
}
深克隆第二种方式
@Override
protected Object clone() throws CloneNotSupportedException {
try {
ObjectOutputStream oos = new ObjectOutputStream(new ByteArrayOutputStream());
oos.writeObject(this);
oos.flush();
oos.close();
//反序列化
byte[] arr = new ByteArrayOutputStream().toByteArray();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(arr));
Object object = ois.readObject();
return object;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.clone();
}
}