美文网首页
Java☞克隆

Java☞克隆

作者: 小明今晚加班 | 来源:发表于2019-05-29 21:30 被阅读0次

    在基类Object中,有个clone方法,可产生一个前期对象的克隆,克隆对象是原对象的拷贝,由于引用类型的存在,又有了深克隆和浅克隆之分,若克隆对象中存在引用类型的属性,深克隆将会将此属性完全拷贝一份;而浅克隆仅仅是拷贝一份此属性的引用。其实在克隆的时候最需要注意的是对象和数组,这两种类型一定要铭记深度克隆的方法。

    1. clone方法是Object类的,并不是Cloneable接口的,Cloneable只是一个标记接口,标记接口是标记实现该接口的类具有某种该接口标记的功能。常见的标记接口有三个:Cloneable、Serializable、RandomAccess,如果没有实现Cloneable接口,那么调用clone方法就会报CloneNotSupportException异常。
    2. 重写clone方法,内部仅仅是调用了父类的clone方法,当然这只是浅克隆的clone方法,深克隆就要修改了。
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    
    1. 给出一张前人画的克隆图,简直太容易理解了:


      浅克隆.png
      深克隆.png

    给出两种深克隆的方法

    1. 实现Cloneable接口,重写clone方法(需要嵌套clone方法)

    package cn.ihep.clone;
    
    import java.util.Arrays;
    
    /**
     * 测试克隆---深度克隆,浅度克隆
     * 
     * @author xiaoming
     *
     */
    public class CloneTest implements Cloneable {
    
        private String name;
        private int age;
        private String[] hobby;
        private int[] nums;
    
        public CloneTest(String name, int age, String[] hobby, int[] nums) {
            super();
            this.name = name;
            this.age = age;
            this.hobby = hobby;
            this.nums = nums;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String[] getHobby() {
            return hobby;
        }
    
        public void setHobby(String[] hobby) {
            this.hobby = hobby;
        }
    
        public int[] getNums() {
            return nums;
        }
    
        public void setNums(int[] nums) {
            this.nums = nums;
        }
    
        @Override
        protected Object clone() {
            CloneTest clt = null;
            try {
                clt = (CloneTest) super.clone();
                //这里必须要加上hobby和nums的克隆(数组和对象都需要添加该方法)
                clt.hobby = hobby.clone();
                clt.nums = nums.clone();
                return clt;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return clt;
        }
    
        @Override
        public String toString() {
            return "CloneTest [name=" + name + ", age=" + age + ", hobby=" + Arrays.toString(hobby) + ", nums="
                    + Arrays.toString(nums) + "]";
        }
    
        public static void main(String[] args) {
            String name = "xiaoming";
            int age = 17;
            String[] strs = { "a", "b" };
            int[] nums = { 1, 2, 3 };
            CloneTest t = new CloneTest(name, age, strs, nums);
            CloneTest tNew = (CloneTest) t.clone();
            System.out.println(t);
            System.out.println(tNew);
            nums[0] = 250;
            strs[0] = "hahah";
            t.setNums(nums);
            t.setHobby(strs);
            System.out.println(t);
            System.out.println(tNew);
        }
    }
    -----------------
    输出结果 :
    CloneTest [name=xiaoming, age=17, hobby=[a, b], nums=[1, 2, 3]]
    CloneTest [name=xiaoming, age=17, hobby=[a, b], nums=[1, 2, 3]]
    CloneTest [name=xiaoming, age=17, hobby=[hahah, b], nums=[250, 2, 3]]
    CloneTest [name=xiaoming, age=17, hobby=[a, b], nums=[1, 2, 3]]
    

    2. 通过序列化的方法来实现深度克隆

    使用这种方法的时候,克隆的对象一定要实现Serializable接口。

    package cn.ihep.clone;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    import java.util.Arrays;
    
    /**
     * 通过序列化来实现深度克隆
     * 
     * @author xiaoming
     *
     */
    public class CloneBySerializable implements Serializable {
        private static final long serialVersionUID = 1L;
    
        private String name;
        private int age;
        private String[] hobby;
        private int[] nums;
    
        public CloneBySerializable(String name, int age, String[] hobby, int[] nums) {
            super();
            this.name = name;
            this.age = age;
            this.hobby = hobby;
            this.nums = nums;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String[] getHobby() {
            return hobby;
        }
    
        public void setHobby(String[] hobby) {
            this.hobby = hobby;
        }
    
        public int[] getNums() {
            return nums;
        }
    
        public void setNums(int[] nums) {
            this.nums = nums;
        }
    
        @Override
        public String toString() {
            return "CloneTest [name=" + name + ", age=" + age + ", hobby=" + Arrays.toString(hobby) + ", nums="
                    + Arrays.toString(nums) + "]";
        }
    
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            String name = "xiaoming";
            int age = 17;
            String[] strs = { "a", "b" };
            int[] nums = { 1, 2, 3 };
            CloneBySerializable t = new CloneBySerializable(name, age, strs, nums);
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            ObjectOutputStream oo = new ObjectOutputStream(bo);
            oo.writeObject(t);
            ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
            ObjectInputStream oi = new ObjectInputStream(bi);
            CloneBySerializable cloneT = (CloneBySerializable) oi.readObject();
            System.out.println(t);
            System.out.println(cloneT);
            nums[0] = 250;
            strs[0] = "hahah";
            t.setNums(nums);
            t.setHobby(strs);
            System.out.println(t);
            System.out.println(cloneT);
        }
    }
    --------------------------------
    输出结果:
    CloneTest [name=xiaoming, age=17, hobby=[a, b], nums=[1, 2, 3]]
    CloneTest [name=xiaoming, age=17, hobby=[a, b], nums=[1, 2, 3]]
    CloneTest [name=xiaoming, age=17, hobby=[hahah, b], nums=[250, 2, 3]]
    CloneTest [name=xiaoming, age=17, hobby=[a, b], nums=[1, 2, 3]]
    

    通过序列化的方法来实现深克隆还是一个比较常用的操作,比如有一个列表list,里面存储的是User对象,即List<User> list = new ArrayList<>();如果想把列表list给拷贝一份给cloneList,该如何操作呢?
    这个时候序列化的方式首选,前提User类要实现Serializable接口。如下:

    package cn.ihep.clone;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;
    
    import org.eclipse.jdt.internal.compiler.batch.Main;
    
    public class User implements Serializable {
        private static final long serialVersionUID = 1L;
    
        private String name;
        private int age;
    
        public User(String name, int age) {
            super();
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "User [name=" + name + ", age=" + age + "]";
        }
    
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            User u1 = new User("xiaoming", 18);
            User u2 = new User("ahua", 45);
            User u3 = new User("zhangsan", 19);
            User u4 = new User("lisi", 20);
            List<User> list = new ArrayList<>();
            list.add(u1);
            list.add(u2);
            list.add(u3);
            list.add(u4);
    
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            ObjectOutputStream oo = new ObjectOutputStream(bo);
            oo.writeObject(list);
    
            ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
            ObjectInputStream oi = new ObjectInputStream(bi);
            List<User> cloneList = (List<User>) oi.readObject();
            System.out.println(list);
            System.out.println(cloneList);
            
            list.get(0).setName("zhaoxiaoming");
            list.get(0).setAge(100);
            System.out.println(list);
            System.out.println(cloneList);
        }
    }
    --------------------------------
    输出结果:
    [User [name=xiaoming, age=18], User [name=ahua, age=45], User [name=zhangsan, age=19], User [name=lisi, age=20]]
    [User [name=xiaoming, age=18], User [name=ahua, age=45], User [name=zhangsan, age=19], User [name=lisi, age=20]]
    [User [name=zhaoxiaoming, age=100], User [name=ahua, age=45], User [name=zhangsan, age=19], User [name=lisi, age=20]]
    [User [name=xiaoming, age=18], User [name=ahua, age=45], User [name=zhangsan, age=19], User [name=lisi, age=20]]
    

    注意:String类型的变量在克隆时候外表效果看起来和基本数据类型一样,其实不是这样的,因为String类型是不可改变类型,所以,当你修改字符串str的值的时候,是直接在堆上又new出来了一个对象,同时你的引用地址也跟着指向这个新地址了,所以看起来“貌似”不符合上述对象克隆的特征,事实上他们并冲突,就是因为String类型特殊。

    相关文章

      网友评论

          本文标题:Java☞克隆

          本文链接:https://www.haomeiwen.com/subject/ukvutctx.html