天天看點

關于clone對象的拷貝

clone為Object類的一個本地方法

protected native Object clone() throws CloneNotSupportedException;
           

要想對象具有拷貝功能則需要該類實作Cloneable接口,表示該類允許拷貝,并且在類中自定義clone調用Object類提供的繼承權限clone方法。

關于對象的兩種拷貝方式

1.淺拷貝

class Teacher implements Cloneable {
            private String name;
            private Integer age;
            public Teacher(String name, Integer age) {
                this.name = name;
                this.age = age;
            }
            @Override
            protected Object clone() throws CloneNotSupportedException {
                return super.clone();
            }
        }
        class Student implements Cloneable {
        private String name;
        private Integer age;
        private Teacher teacher;
        public Student(String name, Integer age, Teacher teacher) {
            this.name = name;
            this.age = age;
            this.teacher = teacher;
        }
         public Teacher getTeacher() {
            return teacher;
        }
        public void setTeacher(Teacher teacher) {
            this.teacher = teacher;
        }
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    public class TestClone {
        public static void main(String[] args) throws Exception {
            Teacher teacher = new Teacher("lxy", 17);
            Student student = new Student02("abc", 12, teacher);
            Student clone = (Student)student.clone();
            System.out.println(student == clone);//false
             System.out.println(student.getTeacher()==clone.getTeacher());//true
        }
    }
           

由上面結果可以看出,淺拷貝出來的對象保留着原對象的中其他類的引用,在拷貝出來的對象中沒用建立其他類新的對象。

2.深拷貝

深拷貝:對拷貝出來的對象對于其所有引用建立産生新的對象。

實作方式:

1,包含的其他類實作cloneable接口,并且其他類的拷貝是來自自身類的clone方法

2,使用序列化,本類和本類包含的其他類實作Serializable。

1.代碼實作

class Teacher implements Cloneable {
    private String name;
    private Integer age;
    public Teacher(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Student implements Cloneable {
    private String name;
    private Integer age;
    private Teacher teacher;

    public Student(String name, Integer age, Teacher teacher) {
        this.name = name;
        this.age = age;
        this.teacher = teacher;
    }
    @Override
    protected Student clone() throws CloneNotSupportedException {
        Student temp = (Student) super.clone();
        temp.teacher = (Teacher) this.teacher.clone();
        return temp;
    }
    public Teacher getTeacher() {
        return teacher;
    }
    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }
}
public class TestClone{
    public static void main(String[] args) throws Exception {
        Teacher teacher = new Teacher("lxy", 17);
        Student student = new Student("abc", 12, teacher);
        Student clone =student.clone();
        System.out.println(student == clone);//false
        System.out.println(student.getTeacher()==clone.getTeacher());//false
    }
}
           

2.代碼實作

class Teacher implements Serializable {
    private String name;
    private Integer age;
    public Teacher(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}
class Student implements Serializable {
    private String name;
    private Integer age;
    private Teacher teacher;
    public Student(String name, Integer age, Teacher teacher) {
        this.name = name;
        this.age = age;
        this.teacher = teacher;
    }
    public Student cloneObject() throws IOException, ClassNotFoundException {
        ByteOutputStream bos = new ByteOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.getBytes());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (Student) ois.readObject();
    }
 public Teacher getTeacher() {
        return teacher;
    }
    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }
}
  public class TestClone {
        public static void main(String[] args) throws Exception {
            Teacher teacher = new Teacher("lxy", 17);
            Student student = new Student02("abc", 12, teacher);
            Student clone =student.clone();
            System.out.println(student == clone);//false
             System.out.println(student.getTeacher()==clone.getTeacher());//false
        }
    }
           

由結果可知拷貝出來的對象中對于其他對象的引用為新值。對任意對象的修改都不會對其他對象産生影響。

clone的替換方案

使用clone方法拷貝一個對象,過程比較複雜又有風險,建議不要用clone,可以使用拷貝構造函數。

代碼如下

class Teacher {
    public Teacher() {
    }

    public Teacher(Teacher teacher) {
    }
}

class Person {
    String name;
    Teacher teacher;

    public Person() {
    }

    public Person(String name, Teacher teacher) {
        this.name = name;
        this.teacher = teacher;
    }

    public Person(Person person) {
        name = new String(person.name);
        teacher = new Teacher(person.teacher);
    }
}

public class Test {
    public static void main(String[] args) {
        Person p = new Person("lyx", new Teacher());
        Person p1 = new Person(p);
        System.out.println(p == p1);//false
        System.out.println(p.name);//lyx
        System.out.println(p1.name);//lyx
        p.name = "abc";
        System.out.println(p.name);//abc
        System.out.println(p1.name);//lyx
        System.out.println(p.teacher == p1.teacher);false
    }
}
           

繼續閱讀