一、直接赋值复制
直接赋值。在 Java 中,Student stu2= stu1,我们需要理解的是这实际上复制的是引用,也就是 说 stu1 和 stu2 指向的是同一个对象。因此,当 stu1变化的时候,stu2 里面的成员变量也会跟 着变化。
二、浅克隆(复制引用但不复制引用的对象)
创建一个新对象,然后将当前对象的非静态字段复制到该新对象,
如果字段是值类型的, 那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象
。 因此,原始对象及其副本引用同一个对象。
一般步骤是:
- 被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常), 该接口为标记接口(不含任何方法)
- 覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象。(native为本地方法)
class Resume implements Cloneable{
public Object clone() {
try {
return (Resume)super.clone();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
三、深克隆(复制对象和其应用对象)
深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。
class Student implements Cloneable {
String name;
int age;
Professor p;
Student(String name, int age, Professor p) {
this.name = name;
this.age = age;
this.p = p;
}
public Object clone() {
Student o = null;
try {
o = (Student) super.clone();
} catch (CloneNotSupportedException e) {
System.out.println(e.toString());
}
o.p = (Professor) p.clone();
return o;
}
}
四、序列化(深 clone 一中实现)
- 在 Java 语言里深复制一个对象,常常可以先使对象实现 Serializable 接口,然后把对 象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。
- 如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时我们可以用序列化的方式来实现对象的深克隆。
public class Student {
// 最好是显式声明ID
private static final long serialVersionUID = 890989298572941L;
public Address address;
public Student myclone() {
Student student = null;
// 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(stream);
oos.writeObject(this);
// 将流序列化成对象
ByteArrayInputStream inputStream = new ByteArrayInputStream(stream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
student = (Student) objectInputStream.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return student;
}
}
class Address implements Serializable {
private static final long serialVersionUID = 900000013109L;
public String name = "";
public Address(String name) {
this.name = name;
}
@Override
public String toString() {
return "地址为:" + name;
}
}