• java浅拷贝和深拷贝(基础也是很重要的)


    对象的copy你兴许只是懵懂,或者是并没在意,来了解下吧。

    对于的github基础代码https://github.com/chywx/JavaSE

    最近学习c++,跟java很是相像,在慕课网学习c++也算是重温习了下java基础

    明白了当初讲师一直强调java传递的话只有值传递,不存在引用传递,为什么一直要重复这,既然只有值传递,为啥还强调不是引用传递

    毛病啊这是

     学了c++才知道,原来c++有值传递,引用传递的说法,但是java只是值传递

    最简单的理解就是对于方法调用

    比如 f(int a,int b) 这是值传递,传递过来的值不会被修改。

    再如 f(int &a,int &b)这是引用传递,传递过来的值会被修改

     

    步入正轨,说一说java的浅拷贝(Shallow Copy)、深拷贝(Deep Copy)。

    浅拷贝(Shallow Copy):①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。②对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。

    通过示例来了解下,

     一:

      使用构造函数实现copy

    public class Person {
        public static void main(String[] args) {
            Son s = new Son(10);
            Person p1 = new Person("大海", s);
            Person p2 = new Person(p1);
            p1.setSonName("小海");
            p1.getSon().setAge(12);
            System.out.println("p1:" + p1);// p1:Person [sonName=小海, son=Son [age=10]]
            System.out.println("p2:" + p2);// p2:Person [sonName=大海, son=Son [age=10]]
    
        }
    
        private String sonName;
        private Son son;
    
        // 自定义拷贝函数
        public Person(Person person) {
            this.sonName = person.sonName;
            this.son = person.son;
        }
    
        public Person(String sonName, Son son) {
            super();
            this.sonName = sonName;
            this.son = son;
        }
    
        public String getSonName() {
            return sonName;
        }
    
        public void setSonName(String sonName) {
            this.sonName = sonName;
        }
    
        public Son getSon() {
            return son;
        }
    
        public void setSon(Son son) {
            this.son = son;
        }
    
        @Override
        public String toString() {
            return "Person [sonName=" + sonName + ", son=" + son + "]";
        }
    
    }
    
    class Son {
        private int age;
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public Son(int age) {
            super();
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Son [age=" + age + "]";
        }
    
    }

    结果

    p1:Person [sonName=小海, son=Son [age=12]]
    p2:Person [sonName=大海, son=Son [age=12]]

    对于上面的实例,该person对象有两个成员,一个基本类型,一个引用类型,结果是拷贝出来的对象,基本类型的那个成员真正的实现了copy。

     二:

      使用自带的clone方法,需要实现cloneable接口,不然会

    Exception in thread "main" java.lang.CloneNotSupportedException:

     

    public class Person2 implements Cloneable {
        public static void main(String[] args) throws CloneNotSupportedException {
            Son2 son1 = new Son2(10);
    
            Person2 person1 = new Person2("大海", son1);
            Person2 person2 = (Person2) person1.clone();
            person2.setSon2Name("小海");
            person2.getSon2().setAge(12);
            System.out.println(person1);
            System.out.println(person2);
        }
    
        public Person2(String son2Name, Son2 son2) {
            super();
            this.son2Name = son2Name;
            this.son2 = son2;
        }
    
        private String son2Name;
        private Son2 son2;
    
        public String getSon2Name() {
            return son2Name;
        }
    
        public void setSon2Name(String son2Name) {
            this.son2Name = son2Name;
        }
    
        public Son2 getSon2() {
            return son2;
        }
    
        public void setSon2(Son2 son2) {
            this.son2 = son2;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    
        @Override
        public String toString() {
            return "Person2 [son2Name=" + son2Name + ", son2=" + son2 + "]";
        }
    
    }
    
    class Son2 {
        private int age;
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Son2 [age=" + age + "]";
        }
    
        public Son2(int age) {
            super();
            this.age = age;
        }
    
    }

     

     结果:

    Person2 [son2Name=大海, son2=Son2 [age=12]]
    Person2 [son2Name=小海, son2=Son2 [age=12]]

    使用自带的copy实现浅拷贝

    ---------------------------------------------------------------------------------------------------

    深拷贝

      相对于浅拷贝而言,对于引用类型的修改,并不会影响到对应的copy对象的值。每一层的每个对象都进行浅拷贝=深拷贝。

    一:

      还是使用clone方法,只不过得手动重写一下。

    上代码

    public class Person3 implements Cloneable {
        public static void main(String[] args) throws CloneNotSupportedException {
            Son3 son1 = new Son3(10);
            Person3 person1 = new Person3("大海", son1);
            Person3 person2 = (Person3) person1.clone();
            person2.setSon2Name("小海");
            person2.getSon3().setAge(12);//修改对应的引用对象的值。
            System.out.println(person1);
            System.out.println(person2);
        }
    
        public Person3(String son2Name, Son3 son3) {
            super();
            this.son2Name = son2Name;
            this.son3 = son3;
        }
    
        private String son2Name;
        private Son3 son3;
    
        public String getSon2Name() {
            return son2Name;
        }
    
        public void setSon2Name(String son2Name) {
            this.son2Name = son2Name;
        }
    
        public Son3 getSon3() {
            return son3;
        }
    
        public void setSon3(Son3 son3) {
            this.son3 = son3;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            Person3 clone = (Person3) super.clone();
            clone.setSon3((Son3) clone.getSon3().clone());
            return clone;
        }
    
        @Override
        public String toString() {
            return "Person3 [son2Name=" + son2Name + ", son3=" + son3 + "]";
        }
    
    }
    
    class Son3 implements Cloneable {
        private int age;
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Son2 [age=" + age + "]";
        }
    
        public Son3(int age) {
            super();
            this.age = age;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    
    }

     

    结果:

    Person3 [son2Name=大海, son3=Son2 [age=10]]

    Person3 [son2Name=小海, son3=Son2 [age=12]]

    方法二:

      显然对于多个对象的话,显然就很吃力。可以使用另一种方式,

      将对象序列化为字节序列后,默认会将该对象的整个对象图进行序列化,再通过反序列即可完美地实现深拷贝。

     

    public class Person4 implements Serializable {
        public static void main(String[] args) throws CloneNotSupportedException, ClassNotFoundException, IOException {
            Son4 son = new Son4(10);
            Person4 person1 = new Person4("大海", son);
            //通过序列化方法实现深拷贝
            ByteArrayOutputStream bos=new ByteArrayOutputStream();
            ObjectOutputStream oos=new ObjectOutputStream(bos);
            oos.writeObject(person1);
            oos.flush();
            ObjectInputStream ois=new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
            Person4 person2=(Person4)ois.readObject();
            person1.setSon4Name("小海");
            person1.getSon4().setAge(12);
            System.out.println(person1.toString());
            System.out.println(person2.toString());
        }
    
        public Person4(String son4Name, Son4 son4) {
            super();
            this.son4Name = son4Name;
            this.son4 = son4;
        }
    
        private String son4Name;
        private Son4 son4;
    
        public String getSon4Name() {
            return son4Name;
        }
    
        public void setSon4Name(String son4Name) {
            this.son4Name = son4Name;
        }
    
        public Son4 getSon4() {
            return son4;
        }
    
        public void setSon4(Son4 son4) {
            this.son4 = son4;
        }
    
        @Override
        public String toString() {
            return "Person4 [son4Name=" + son4Name + ", son4=" + son4 + "]";
        }
    }
    
    class Son4 implements Serializable {
        private int age;
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "Son2 [age=" + age + "]";
        }
    
        public Son4(int age) {
            super();
            this.age = age;
        }
    
    }

    这是实现序列化接口方案,nice. 

    perfect!!!到位

     记录下听得歌曲。

        绝世
                (张克帆)
    世间种种的诱惑
    不惊不扰我清梦
    山高路远不绝我
    追踪你绝美的笑容
    登高一呼时才懂
    始终在为你心痛
    俯首对花影摇动
    都是东风在捉弄
    世间种种的迷惑
    都是因你而猜错
    水光月光又交融
    描述这朗朗的夜空
    生死到头的相从
    似狂花落叶般从容
    当一切泯灭如梦
    就在远山被绝世尘封            

     

  • 相关阅读:
    初识算法和数据结构
    cookies、sessionStorage和localStorage解释及区别
    常用元素操作api之select下拉列表操作(八)
    常用元素操作api之定位常见alert框操作(七)
    常用元素操作api之定位元素操作iframe(六)
    常用元素操作api之select下拉列表层级定位操作(五)
    常用元素操作api之定位一组元素操作(四)
    常用元素操作api之等待时间标操作(三)
    Java实现获取命令行中获取指定数据
    Java格式化字符串Format
  • 原文地址:https://www.cnblogs.com/chywx/p/9574586.html
Copyright © 2020-2023  润新知