深克隆与浅克隆
1.内部类:
如果内部类为非静态内部类,需要通过外部类的实例来new,比如:
InnerClass为AA的内部类,在想得到InnerClass的实例时需要:
AA a = new AA();
InnerClass ic = a.new InnerClass();
或
AA a = new AA();
AA.InnerClass ic = a.new InnerClass();
如果内部类为静态内部类,可直接new:
AA.InnerClass ic = new InnerClass();
或
InnerClass ic = new InnerClass();
2.浅克隆
无论深克隆还是浅克隆在针对基本数据类型的克隆是相同的,但是在针对应用数据类型进行克隆的时候就不一样了,因为基本数据类型是在栈中存储,引用数据类型是在堆中存储的。
浅克隆代码:
public class AA {
public static void main(String[] args) {
AA a = new AA();
Name name = a.new Name("张", "三");
User user1 = a.new User();//被克隆对象
User user2 = a.new User();//克隆后对象
user1.setAge(12);
user1.setId(1);
user1.setName(name);
try {
user2 = user1.clone();
user2.setId(2);
user2.getName().setLastName("四");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("user1:" + user1.toString());
System.out.println("user2:" + user2.toString());
}
//克隆对象
public class User implements Cloneable{
public int id;
public int age;
public Name name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
@Override
public String toString() {
return "id:" + id + ",age:" + age + ",address:" + name;
}
@Override
public User clone() throws CloneNotSupportedException {
User u = (User) super.clone();
return u;
}
}
//引用对象
public class Name {
private String firstName;
private String lastName;
public Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String toString() {
return "firstName:" + firstName + ",lastName:" + lastName;
}
}
}
既只要被克隆的类实现Cloneable接口,并重写clone()方法即可。
输出结果:
user1:id:1,age:12,address:firstName:张,lastName:四
user2:id:2,age:12,address:firstName:张,lastName:四
可以看出在克隆后的对象基本数据类型的改变不影响被克隆对象的数据,但是引用数据类型改变被克隆的对象也随之改变了!
3.深克隆
深克隆可以通过在被克隆的引用类型的类也实现Cloneable接口并实现clone()方法,在克隆对象的clone()方法里面的引用对象进行克隆即可:
//引用对象重写clone()方法
@Override
public Name clone() throws CloneNotSupportedException {
return (Name) super.clone();
}
@Override
public User clone() throws CloneNotSupportedException {
User u = (User) super.clone();
u.name = name.clone();//克隆对象添加引用对象的克隆
return u;
}
输出结果
user1:id:1,age:12,address:firstName:张,lastName:三
user2:id:2,age:12,address:firstName:张,lastName:四
但是上面这种方式显得很重复,在应用对象过多的时候写起来很繁琐,代码的重复率太高,所以可以使用对象的序列化,即先将对象写入到流中,然后通过读取对象进行反序列化进行复制:
克隆对象方法:
public static Object cloneObject(Object obj) throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();//先创建写字节数组流
ObjectOutputStream oos = new ObjectOutputStream(baos);//再创建写对象流,将产生的字节流写到上面的字节数组流对象中
oos.writeObject(obj);//开始写传入的对象
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());//创建读字节数组流,读取存储写出的字节数组流
ObjectInputStream ois = new ObjectInputStream(bais);//将读取的字节数组流转为读对象流
return ois.readObject();//将对象流转为对象
}
调用
public static void main(String[] args) {
AA a = new AA();
Name name = a.new Name("张", "三");
User user1 = a.new User();
User user2 = a.new User();
user1.setAge(12);
user1.setId(1);
user1.setName(name);
try {
user2 = (User) cloneObject(user1);
user2.setId(2);
user2.getName().setLastName("四");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("user1:" + user1.toString());
System.out.println("user2:" + user2.toString());
}
输出结果
user1:id:1,age:12,address:firstName:张,lastName:三
user2:id:2,age:12,address:firstName:张,lastName:四
注意:在进行序列化的时候涉及到的类要进行序列化,既对应的类要实现Serializable接口,在开始说的内部类注意如果非静态内部类进行序列化那么外部类和内部类必须要实现Serializable接口,如果静态内部类进行序列化则内部类必须实现Serializable,外部类是否实现Serializable不影响,因为非静态内部类对外部类有一个隐式的引用。