首页 > 编程语言 >Java浅拷贝深拷贝

Java浅拷贝深拷贝

时间:2022-08-16 11:00:31浏览次数:51  
标签:Java name clone Person person1 拷贝 age


Java浅拷贝深拷贝

浅拷贝和深拷贝涉及到了Object类中的clone()方法

 

 

实现浅拷贝

浅拷贝的实现需要类重写clone()方法

浅拷贝会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝

  • 如果属性是基本类型,拷贝的就是基本类型的值;

  • 如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象,导致两个对象的引用不等。

实现浅拷贝很简单只需要将类实现Cloneable接口然后重写clone方法即可

 class Person implements Cloneable {
     String name;
     int age;
 ​
     public Person() {
    }
 ​
     public Person(String name, int age) {
         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;
    }
 ​
     /**
          * 重写clone()方法
          *
          * @return
          * @throws CloneNotSupportedException
          */
     @Override
     protected Object clone() throws CloneNotSupportedException {
         return super.clone();
    }
 ​
     @Override
     public String toString() {
         return "Person{" +
             "name='" + name + '\'' +
             ", age=" + age +
             '}';
    }
 }

测试浅拷贝特性

 public void testClone() throws CloneNotSupportedException {
     Person person1 = new Person();
     person1.setName("ccy");
     person1.setAge(20);
     Person person2 = (Person) person1.clone();
     //查看浅拷贝效果
     System.out.println(person1);
     System.out.println(person2);
     System.out.println(person1.getName() == person2.getName());
     //验证clone()的特性
     System.out.println(person1.clone() != person1);
     System.out.println(person1.clone().getClass() == person1.getClass());
     //如果是基本类型浅拷贝直接赋值值,如果是引用类型浅拷贝指向其内存地址即共享内存地址
     //改变person1的引用类型String属性的值,引用发生改变
     person1.setName("zfs");
     System.out.println(person2.getName());
 }

 

 

实现深拷贝

对于上述的问题虽然拷贝的两个对象不同,但其内部的一些引用还是相同的,怎么样绝对的拷贝这个对象,使这个对象完全独立于原对象呢?就使用我们的深拷贝了。深拷贝:在对引用数据类型进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量。

在具体实现深拷贝上,这里提供两个方式,重写clone()方法和序列法。

重写clone()方法

如果使用重写clone()方法实现深拷贝,那么要将类中所有自定义引用变量的类也去实现Cloneable接口实现clone()方法。对于字符类可以创建一个新的字符串实现拷贝。但是对于自定义类需要实现cloneable重写clone,这样做就太麻烦了所以我们使用序列化

序列化

序列化后将二进制字节流内容写到一个媒介(文本或字节数组),然后是从这个媒介读取数据,原对象写入这个媒介后拷贝给clone对象,原对象的修改不会影响clone对象,因为clone对象是从这个媒介读取。

熟悉对象缓存的知道我们经常将Java对象缓存到Redis中,然后还可能从Redis中读取生成Java对象,这就用到序列化和反序列化。一般可以将Java对象存储为字节流或者json串然后反序列化成Java对象。因为序列化会储存对象的属性但是不会也无法存储对象在内存中地址相关信息。所以在反序列化成Java对象时候会重新创建所有的引用对象。

在具体实现上,自定义的类需要实现Serializable接口

 class Person implements Serializable {
     String name;
     int age;
 ​
     public Person() {
    }
 ​
     public Person(String name, int age) {
         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 "Person{" +
             "name='" + name + '\'' +
             ", age=" + age +
             '}';
    }
 ​
     protected Person deepClone() throws Exception {
         //序列化
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         ObjectOutputStream oos = new ObjectOutputStream(bos);
 ​
         oos.writeObject(this);
 ​
         //反序列化
         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
         ObjectInputStream ois = new ObjectInputStream(bis);
 ​
         return (Person) ois.readObject();
    }
 }

测试方法

 public void testClone() throws Exception {
     Person person1 = new Person();
     person1.setName("ccy");
     person1.setAge(20);
     Person person2 = person1.deepClone();
     System.out.println(person1.getName() == person2.getName());
 }

 

 

可以看到两个引用对象的地址并不同,成功实现了深拷贝

标签:Java,name,clone,Person,person1,拷贝,age
From: https://www.cnblogs.com/ccywmbc/p/16590857.html

相关文章

  • Java注解最全详解(超级详细)
    Java注解是一个很重要的知识点,掌握好Java注解有利于学习Java开发框架底层实现。@mikechenJava注解定义Java注解又称Java标注,是在JDK5时引入的新特性,注解(也被称为元数......
  • JAVA的环境搭建
    第一章 JAVA的环境第一节 Java三大版本JavaSE:标准版(桌面程序、控制台开发)StandardEditor(标准版)J2SE包含构成Java语言核心的类,定位在个人计算机上的应用。这个版本......
  • kettle spoon 修改java安装位置
    CMD运行java-verbose查找JAVA安装位置找到kettlespoon安装目录找到一下位置修改@echooffsetlocalcd/D%~dp0REM****************************************......
  • java web 判断请求是手机端还是PC端(代码库)
    判断类packageconfig;importjava.util.regex.Matcher;importjava.util.regex.Pattern;publicclassCheckMobile{privateCheckMobile(){}//......
  • Javaweb08-Ajax项目-分页条件查询 + 增删改
    1、登录1.1登录form表单<formaction="<%=request.getContextPath()%>/loginAnime"method="get"><tableborder="1px"align="center"width="40%"cellspacing="......
  • 【JAVA UI】abilitySlice或ability以Action方式跳转
    ​参考资料PageAbility基本概念【HarmonyOS】【JAVAUI】abilitySlice和ability跳转方式【HarmonyOS】【FAQ】鸿蒙问题合集4代码实现1、准备工作新建一个TwoAbilit......
  • 【Java面试】聊聊你知道的设计模式
    “聊聊你知道的设计模式!”这个问题很简单,但是要让面试官认可你的回答,那还是得花点心思。大家好,我是Mic,一个工作了14年的Java程序员。今天给大家分享一下,当遇到这种比较......
  • windows查看java进程情况
    1.场景有时候我们启动了多个java程序,需要查看各个java程序占用的的内存情况。打开任务管理器选择“进程”,发现有好多java.exe进程,无法直接查看内存使用情况。 jconsol......
  • Day3(复习:java流程控制)
    Java流程控制 Scanner对象用来获取用户的输入基础语法:Scanners=newScanner(System.in) 通过Scanner类的next()与nextLine()方法获取输入的字符串,在读取器要......
  • JavaWeb阶段性项目2:QQZone项目梳理
    前置知识前置准备知识准备已掌握JavaSE/MySQL/JDBC+HTML/CSS/JavaScript基础并已完成了Javaweb前置知识的学习01-JavaWeb-HTML初识02-JavaWeb-CSS初识03-JavaWeb-......