美文网首页
Java 浅拷贝和深拷贝 拷贝和复制

Java 浅拷贝和深拷贝 拷贝和复制

作者: Duskry | 来源:发表于2020-04-20 23:31 被阅读0次

    Java 复制与拷贝

    大纲

    image

    浅拷贝和深拷贝

    浅拷贝就是复制对象的一个精确副本

    ==对于基本数据类型就是复制值,对于引用数据类型而言就是复制对象地址==

    深拷贝就是复制对象时

    会给==引用数据类型生成一个新的空间==

    image

    浅拷贝

    ==基本数据类型不论是浅拷贝还是深拷贝都是传递值==

    对于引用数据类型而言

    浅拷贝只是拷贝了地址

    一旦修改就会引起源数据的修改

    ==大多数对象的拷贝==一般都是浅拷贝

    深拷贝

    ==基本数据类型不论是浅拷贝还是深拷贝都是传递值==

    对于引用数据而言

    深拷贝实实在在从新创建了一个内存区域存放一样的数据对象

    这样修改是完全独立的

    ==深拷贝一般要自己实现==

    一(二)维数组的拷贝

    先看一个实验例子

    public static void TlistClone(){
            
            System.out.println("一维数组(基本数据包装对象)的clone是克隆值  但是都是基本数据类型的所以值不同");
            Integer[]  d1= new Integer[]{1,1,2,3};
            Integer[]  d2 = d1.clone();
            d2[1]=Integer.valueOf(333);
            Arrays.stream(d1).forEach(integer -> System.out.print(integer+" "));
            System.out.println();
            Arrays.stream(d2).forEach(integer -> System.out.print(integer+" "));
            System.out.println();
            System.out.println("****************************************");
        
        
            System.out.println("一维数组(基本类型)的clone是克隆值 改变的基本数据类型的值");
            int[] a1 = new int[]{1,2,3};
            int[] a2 = a1.clone();
            a2[1]=444;
            System.out.println("源"+Arrays.toString(a1));
            System.out.println("拷贝"+Arrays.toString(a2));
            System.out.println("****************************************");
            System.out.println("一维数组的System.array(Arrays.copyOf())是克隆值  改变的也是基本数据类型的值");
            int[] b1 = new int[]{1,2,3};
            // Arrays.copy 底层是 System.arraycopy();
            int[] b2 = Arrays.copyOf(b1,b1.length);
            b2[1]=1110;
            System.out.println("源"+Arrays.toString(b1));
            System.out.println("拷贝"+Arrays.toString(b2));
            System.out.println("****************************************");
        
        
        
            System.out.println("二维数组的直接clone是浅拷贝,因为二维数组存储其中的一维数组的是地址所以值会同步修改");
            int[][] c1 = new int[][]{{1,2},{3,4}};
            int[][] c2 = c1.clone();
            c2[1][1]=2222;
            c2[0][0]=1;
            System.out.print("源");
            for (int i = 0; i < 2; i++) {
                System.out.println(Arrays.toString(c1[i]));
            }
            System.out.print("拷贝");
            for (int i = 0; i < 2; i++) {
                System.out.println(Arrays.toString(c2[i]));
            }
            System.out.println("****************************************");
        
        
        
            System.out.println("要二维数组正确clone全部值应该对二维数组每一行进行clone");
            int[][] c3 = new int[][]{{1,2},{3,4}};
            int[][] c4 = new int[2][2];
            for (int i = 0; i < 2; i++) {
                c4[i]=c3[i].clone();
            }
            System.out.print("源");
            for (int i = 0; i < 2; i++) {
                System.out.println(Arrays.toString(c3[i]));
            }
            System.out.print("拷贝");
            for (int i = 0; i < 2; i++) {
                System.out.println(Arrays.toString(c4[i]));
            }
            System.out.println("这样才正确");
        }
    

    结果如下

    一维数组(基本数据包装对象)的clone是克隆值  但是都是基本数据类型的所以值不同
    1 1 2 3 
    1 333 2 3 
    ****************************************
    一维数组(基本类型)的clone是克隆值 改变的基本数据类型的值
    源[1, 2, 3]
    拷贝[1, 444, 3]
    ****************************************
    一维数组的System.array(Arrays.copyOf())是克隆值  改变的也是基本数据类型的值
    源[1, 2, 3]
    拷贝[1, 1110, 3]
    ****************************************
    二维数组的直接clone是浅拷贝,因为二维数组存储其中的一维数组的是地址所以值会同步修改
    源[1, 2]
    [3, 2222]
    拷贝[1, 2]
    [3, 2222]
    ****************************************
    要二维数组正确clone全部值应该对二维数组每一行进行clone
    源[1, 2]
    [3, 4]
    拷贝[1, 2]
    [3, 4]
    这样才正确
    

    对象的拷贝

    对象stu类

    class Stu implements Cloneable,Serializable{
        // 实现Cloneable是为了clone方法 ,实现Serializable是为了序列化对象
        int id;
        String name;
        Location location;
        public Stu(){
            super();
        }
        public Stu(int id, String name,Location location) {
            this.id = id;
            this.name = name;
            this.location =location;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            // 对location进行深拷贝需要传入location
            Stu stu = (Stu) super.clone();
            Location location1 = (Location) stu.getLocation().clone();
            stu.setLocation(location1);
            return stu;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Location getLocation() {
            return location;
        }
    
        public void setLocation(Location location) {
            this.location = location;
        }
        @Override
        public String toString() {
            return "Stu{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", location=" + location +
                    '}';
        }
    }
    

    对象location 类

    class Location implements Cloneable{
        String city;
    
        public Location(String city) {
            this.city = city;
        }
    
        public String getCity() {
            return city;
        }
    
        public void setCity(String city) {
            this.city = city;
        }
    
        @Override
        public String toString() {
            return "Location{" +
                    "city='" + city + '\'' +
                    '}';
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
     
    }
    

    测试类

    public static void ObejctClone() throws CloneNotSupportedException {
    
            System.out.println("****************************************");
            System.out.println("对象的clone(实现Cloneable接口)是默认浅拷贝(即实现接口但是不重写) 引用数据类型会被同步修改了");
            System.out.println("只有重写stu clone 方法的时候传入location的拷贝才可以 这里演示的是正确传入了location的拷贝");
            Location location1 = new Location("格陵兰岛");
            Stu stu1 = new Stu(1,"小明",location1);
            Stu stu2 = (Stu) stu1.clone();
            stu2.setId(2);
            stu2.setName("小红");
            Location location2 = stu2.getLocation();
            location2.setCity("中国");
            System.out.println(stu1);
            System.out.println(stu2);
            System.out.println("重写之后(添加对location的拷贝 两个location不一样了");
            System.out.println("****************************************");
    
    
            System.out.println("对象数组clone方法是浅拷贝");
            Stu[] stus1 = new Stu[]{stu1,stu2};
            Stu[] stus2 = stus1.clone();
            System.out.println("原来");
            Arrays.stream(stus1).forEach(stu -> System.out.print(stu+" "));
            System.out.println();
            Arrays.stream(stus2).forEach(stu -> System.out.print(stu+" "));
            System.out.println();
            System.out.println("更改后");
            stus1[0].setLocation(new Location("日本"));
            stus1[0].setName("小车");
            Arrays.stream(stus1).forEach(stu -> System.out.print(stu+" "));
            System.out.println();
            Arrays.stream(stus2).forEach(stu -> System.out.print(stu+" "));
        }
    

    结果

    ****************************************
    对象的clone(实现Cloneable接口)是默认浅拷贝(即实现接口但是不重写) 引用数据类型会被同步修改了
    只有重写stu clone 方法的时候传入location的拷贝才可以 这里演示的是正确传入了location的拷贝
    Stu{id=1, name='小明', location=Location{city='格陵兰岛'}}
    Stu{id=2, name='小红', location=Location{city='中国'}}
    重写之后(添加对location的拷贝 两个location不一样了
    ****************************************
    对象数组clone方法是浅拷贝
    原来
    Stu{id=1, name='小明', location=Location{city='格陵兰岛'}} Stu{id=2, name='小红', location=Location{city='中国'}} 
    Stu{id=1, name='小明', location=Location{city='格陵兰岛'}} Stu{id=2, name='小红', location=Location{city='中国'}} 
    更改后
    Stu{id=1, name='小车', location=Location{city='日本'}} Stu{id=2, name='小红', location=Location{city='中国'}} 
    Stu{id=1, name='小车', location=Location{city='日本'}} Stu{id=2, name='小红', location=Location{city='中国'}} 
    

    集合对象的拷贝

    public static void ColletionClone() throws IOException, ClassNotFoundException {
        System.out.println("Colletions.copy方法是浅拷贝");
        List<Stu> list = new ArrayList<>();
        list.add(new Stu(1,"a",null));
        list.add(new Stu(2,"b",null));
        List<Stu> list2 = new ArrayList<>();
        list2.add(null);
        list2.add(null);
        Collections.copy(list2,list);
        list.get(1).setName("C");
        System.out.println(list);
        System.out.println(list2);
        System.out.println("************************************");
        System.out.println("addAll方法是浅拷贝");
        List<Stu> liststudent = new ArrayList<>();
        liststudent.add(new Stu(1,"a",null));
        liststudent.add(new Stu(2,"b",null));
        List<Stu> liststudent2 = new ArrayList<>();
        liststudent2.addAll(liststudent);
        liststudent.get(1).setName("C");
        System.out.println(liststudent);
        System.out.println(liststudent2);
        System.out.println("************************************");
        System.out.println("构造方法传入是浅拷贝");
        List<Stu> listcon = new ArrayList<>();
        listcon.add(new Stu(1,"a",null));
        listcon.add(new Stu(2,"b",null));
        List<Stu> listcon2 = new ArrayList<>(listcon);
        listcon.get(1).setName("C");
        System.out.println(listcon);
        System.out.println(listcon2);
        System.out.println("************************************");
        System.out.println("序列化 是深拷贝");
        List<Stu> listserial = new ArrayList<>();
        listserial.add(new Stu(1,"a",null));
        listserial.add(new Stu(2,"b",null));
        List<Stu> listseria2;
        listseria2=deepCopy(listserial);
        listserial.get(1).setName("C");
        System.out.println(listserial);
        System.out.println(listseria2);
    }
    
    

    序列化对象的方法

    public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException {
    
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteOut);
        out.writeObject(src);
    
        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
        ObjectInputStream in = new ObjectInputStream(byteIn);
        @SuppressWarnings("unchecked")
        List<T> dest = (List<T>) in.readObject();
        return dest;
    }
    

    结果:

    Colletions.copy方法是浅拷贝
    [Stu{id=1, name='a', location=null}, Stu{id=2, name='C', location=null}]
    [Stu{id=1, name='a', location=null}, Stu{id=2, name='C', location=null}]
    ************************************
    addAll方法是浅拷贝
    [Stu{id=1, name='a', location=null}, Stu{id=2, name='C', location=null}]
    [Stu{id=1, name='a', location=null}, Stu{id=2, name='C', location=null}]
    ************************************
    构造方法传入是浅拷贝
    [Stu{id=1, name='a', location=null}, Stu{id=2, name='C', location=null}]
    [Stu{id=1, name='a', location=null}, Stu{id=2, name='C', location=null}]
    ************************************
    序列化 是深拷贝
    [Stu{id=1, name='a', location=null}, Stu{id=2, name='C', location=null}]
    [Stu{id=1, name='a', location=null}, Stu{id=2, name='b', location=null}]
    

    总结

    对于基本数据类型而言

    ==没有深拷贝和浅拷贝==,因为都是要修改实际的值

    对于引用对象类型

    ==一般的方法都是浅拷贝==

    ==只有正确重写了clone方法或者序列化了才是深拷贝==

    相关文章

      网友评论

          本文标题:Java 浅拷贝和深拷贝 拷贝和复制

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