java clone

簡介

實現Cloneable接口的類纔可以被克隆,如果不實現該接口,調用Object clone方法會報CloneNotSupportedException:

InvokingObject's clone method on an instance that does not implement theCloneableinterface results in the exceptionCloneNotSupportedExceptionbeing thrown.

分類

  1. 淺克隆 指拷貝對象時僅拷貝對象本身中的基本變量,而不拷貝對象包含的引用指向的對象
  2. 深克隆 不僅拷貝對象本身中的基本變量,而且還拷貝對象中包含的引用指向的所有對象

說明

package com.lios.clone;

/**
 * @author LiosWong
 * @description
 * @date 2018/6/25 上午4:11
 */
public class Person implements Cloneable {
    private String name;

    private Worker worker;

    public Person(String name, Worker worker) {
        this.name = name;
        this.worker = worker;
    }

    public String getName() {
        return name;
    }

    public Person setName(String name) {
        this.name = name;
        return this;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) {
        Person p = new Person("lios", new Worker("worker", 25));
        Person p1 = p;
        System.out.println("p:toString:" + p + ",hashCode:" + p.hashCode() + ",Worker:" + p.getWorker().hashCode() + ",name=" + p.getName().hashCode());
        System.out.println("p1:toString:" + p1 + ",hashCode:" + p1.hashCode() + ",Worker:" + p1.getWorker().hashCode() + ",name=" + p1.getName().hashCode());
        System.out.println(p1);


        System.out.println("=====================");

        try {
            Person p2 = (Person) p.clone();
            System.out.println("p:Worker:name:"+p.getWorker().getName());
            System.out.println("p1:Worker:name:"+p1.getWorker().getName());
            System.out.println("p2:Worker:name:"+p2.getWorker().getName());


            System.out.println("p2:toString:" + p2 + ",hashCode:" + p2.hashCode() + ",Worker:" + p2.getWorker().hashCode() + ",name=" + p2.getName().hashCode());
            p.getWorker().setName("workp");
            p.setName("cc");
            System.out.println("p2:toString:" + p2 + ",hashCode:" + p2.hashCode() + ",Worker:" + p2.getWorker().hashCode() + ",name=" + p2.getName().hashCode());
            System.out.println("p:Worker:name:"+p.getWorker().getName());
            System.out.println("p1:Worker:name:"+p1.getWorker().getName());
            System.out.println("p2:Worker:name:"+p2.getWorker().getName());
            System.out.println("p:"+p.getName());
            System.out.println("p1:"+p1.getName());
            System.out.println("p2:"+p2.getName());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }

    public Worker getWorker() {
        return worker;
    }

    public Person setWorker(Worker worker) {
        this.worker = worker;
        return this;
    }

    public static class Worker implements Cloneable {
        private String name;
        private Integer age;

        public Worker(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }

        public String getName() {
            return name;
        }

        public Worker setName(String name) {
            this.name = name;
            return this;
        }

        public Integer getAge() {
            return age;
        }

        public Worker setAge(Integer age) {
            this.age = age;
            return this;
        }
    }
}

執行結果爲:

p:toString:com.lios.clone.Person@2401f4c3,hashCode:604107971,Worker:123961122,name=3321889
p1:toString:com.lios.clone.Person@2401f4c3,hashCode:604107971,Worker:123961122,name=3321889
com.lios.clone.Person@2401f4c3
=====================
p:Worker:name:worker
p1:Worker:name:worker
p2:Worker:name:worker
p2:toString:com.lios.clone.Person@4926097b,hashCode:1227229563,Worker:123961122,name=3321889
p2:toString:com.lios.clone.Person@4926097b,hashCode:1227229563,Worker:123961122,name=3321889
p:Worker:name:workp
p1:Worker:name:workp
p2:Worker:name:workp
p:cc
p1:cc
p2:lios

發現p,p1所有的值都是一致的,當對象p中重置name屬性的值、Worker屬性中name的值後,p、p1、p2中屬性Worker中name屬性值都改變了且值相同,但是p2中的name屬性值沒有變化,下面用圖描述:

p1與p指向堆中的同一塊內存區域,p2雖然與p、p1不是指向同一塊內存區域,但是它們中的Worker屬性都引用同一塊內存區域,其實這就是淺克隆,修改上面clone方法:

@Override
    protected Object clone() throws CloneNotSupportedException {
         Person p = (Person) super.clone();
         p.worker = (Worker) p.getWorker().clone();
         return p;
    }

再執行,結果如下:

p:toString:com.lios.clone.Person@2401f4c3,hashCode:604107971,Worker:123961122,name=3321889
p1:toString:com.lios.clone.Person@2401f4c3,hashCode:604107971,Worker:123961122,name=3321889
com.lios.clone.Person@2401f4c3
=====================
p:Worker:name:worker
p1:Worker:name:worker
p2:Worker:name:worker
p2:toString:com.lios.clone.Person@4926097b,hashCode:1227229563,Worker:1982791261,name=3321889
p2:toString:com.lios.clone.Person@4926097b,hashCode:1227229563,Worker:1982791261,name=3321889
p:Worker:name:workp
p1:Worker:name:workp
p2:Worker:name:worker
p:cc
p1:cc
p2:lios

發現此時p2中屬性Worker中的name屬性值沒有改變,僅僅p、p1中屬性Worker中的name屬性值改變了,圖示:

上面就是深克隆

總結

  1. 對象被clone必須實現Cloneable接口
  2. 深克隆需拷貝對象中包含的引用指向的所有對象
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章