因为每个类直接或间接的父类都是Object,因此它们都含有clone()方法,但是因为该方法是protected,所以都不能在类外进行访问。要想对一个对象进行复制,就需要对clone方法覆盖。
一般步骤是(浅复制):被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常) 该接口为标记接口(不含任何方法)
覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象,(native为本地方法)
class Student implements Cloneable{
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
}
- 如果在Student增加一个对象的引用,如Address,那么上面的student的拷贝,Address属性是Address引用的拷贝,为了达到真正的复制对象,而不是纯粹引用复制。我们需要将Address类可复制化,并且修改clone方法,完整代码如下:
class Address implements Cloneable {
private String add;
public String getAdd() {
return add;
}
public void setAdd(String add) {
this.add = add;
}
@Override
public Object clone() {
Address addr = null;
try{
addr = (Address)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return addr;
}
}
class Student implements Cloneable{
private int number;
private Address addr;
public Address getAddr() {
return addr;
}
public void setAddr(Address addr) {
this.addr = addr;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone(); //浅复制
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
stu.addr = (Address)addr.clone(); //深度复制
return stu;
}
}
public class Test {
public static void main(String args[]) {
Address addr = new Address();
addr.setAdd("杭州市");
Student stu1 = new Student();
stu1.setNumber(123);
stu1.setAddr(addr);
Student stu2 = (Student)stu1.clone();
System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
addr.setAdd("西湖区");
System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
}
}
- 还有一种深拷贝的方式是通过使对象实现Serializable接口,然后把对象(实际上是对象的一个copy),写到一个流里面,便可重复建立对象。这样做被复制的对象与被复制对象里面的引用都是可以被一并深复制的。这种方式比较耗性能,不推荐
“`
public class CloneTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Teacher t = new Teacher();
t.setName(“Teacher xin”);
t.setAge(30);
Student s = new Student();
s.setName("Student xiaoxin");
s.setAge(20);
s.setTeacher(t);
System.out.println("s name="+s.getName());
System.out.println("s age="+s.getAge());
System.out.println("s t name="+s.getTeacher().getName());
System.out.println("s t age="+s.getTeacher().getAge());
System.out.println("-------------------");
Student sCopy = (Student)s.deepCopy();
sCopy.getTeacher().setName("Teacher mao");
//下面运行的结果看出对Student的引用Teacher类进行了深复制
System.out.println("sCopy t name="+sCopy.getTeacher().getName());
System.out.println("-------------------");
System.out.println("s t name="+s.getTeacher().getName());
}
}
class Teacher implements Serializable{
private static final long serialVersionUID = -2380977769309339400L;
private String name;
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Student implements Serializable{
private static final long serialVersionUID = 739748261443702736L;
private String name;
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private Teacher teacher;
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 把对象读到字节流中在读出来
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
public Object deepCopy() throws IOException, ClassNotFoundException{
ByteArrayOutputStream bop = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bop);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bop.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
} “`