javacloneable接口_comparable

javacloneable接口_comparable特点一个类实现了Cloneable接口指向@linkjava.lang.Object#clone()}方法是合法的使得一个field-for-fieldcopy的类的实例的拷贝在不实现Cloneable接口的对象上调用Object的clone方法会导致CloneNotSupportedException异常抛出。按照约定,实现此接口的类应当重写Object.clo…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

特点

一个类实现了Cloneable接口 指向@link java.lang.Object#clone()}
方法是合法的 使得一个 field-for-field copy的类的实例的拷贝

在不实现Cloneable接口的对象上调用Object的clone方法
会导致CloneNotSupportedException异常抛出。

按照约定,实现此接口的类应当重写Object.clone方法 (被保护)带有public

注意 此接口不包含clone方法
因此不可能仅仅依赖实现了这个接口就拷贝一个对象 。
即使这个clone方法 被反射调用 也不能保证成功

java.lang.Object#clone()

创建并返回此对象的副本。复制 可能取决于对象的类。总体的意图是
对应任何对象x 表达式

 x.clone() != x

会是true 并且表达

x.clone().getClass() == x.getClass()

将会是true
但是这些不是绝对要求
通常情况下:

 x.clone().equals(x)

将是true,这不是绝对的要求

按照惯例,返回的对象应该通过调用获得{@code super.clone}.
如果一个class 和 它所有的父类 除了 {@code Object})遵循这个惯例,
它应当是这样的

 x.clone().getClass() == x.getClass()

按照惯例,该方法返回的对象应该是独立的。这个对象(正在被克隆)
为了实现这种独立性,可能需要修改返回的对象的一个或多个字段
在返回之前使用{@code super.clone}
通常,这意味着复制包含内部 深层结构的任何可变对象 正在克隆的对象
和替换这些对象的应用 利用 引用的副本。

如果一个类只包含原始字段或者不可变对象的引用 通常意味着
通过{@code super.clone}返回的对象没有fileds字段需要被修改

{@code clone} 方法给Object对象类 操作一个特别的克隆操作。
首先,如果这个对象的类不实现Cloneable接口 CloneNotSupportedException将会抛出,所有的数组将会被考虑实现接口Cloneable。一个数组类型T[] clone方法的返回的类型是T[] T是一个引用或者基本类型
否则,此方法将创建此类的新实例,然后初始化所有的字段 内容完全是对象的对应字段,如果通过赋值,字段的内容不会拷贝他们自己。因此 这种方法执行对象的“shallow copy”,而不是deep copy

对象的类本身不实现Cloneable接口 所以调用clone方法 在一个对象 它的类是 对象
将抛出一个运行时异常。

浅拷贝和深度拷贝

为什么要克隆?
克隆的对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠clone方法了。那么我把这个对象的临时属性一个一个的赋值给我新new的对象不也行嘛?可以是可以,但是一来麻烦不说,二来,大家通过上面的源码都发现了clone是一个native方法,就是快啊,在底层实现的

Object a=new Object();Object b;b=a;这种形式的代码复制的是引用,即对象在内存中的地址,a和b对象仍然指向了同一个对象。而通过clone方法赋值的对象跟原来的对象时同时独立存在的

ShallowClone
在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。

简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。

  1. 被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常), 该接口为标记接口(不含任何方法)

  2. 覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象。(native为本地方法)

示例

package abc;  

class Address implements Cloneable { 
     
    private String add;  

    public String getAdd() {  
        return add;  
    }  

    public void setAdd(String add) {  
        this.add = add;  
    }  

    @Override  
    public Object clone() {  
        Address addr = null;  
        try{  
            addr = (Address)super.clone();  
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        return addr;  
    }  
}  

class Student implements Cloneable{ 
     
    private int number;  

    private Address addr;  

    public Address getAddr() {  
        return addr;  
    }  

    public void setAddr(Address addr) {  
        this.addr = addr;  
    }  

    public int getNumber() {  
        return number;  
    }  

    public void setNumber(int number) {  
        this.number = number;  
    }  

    @Override  
    public Object clone() {  
        Student stu = null;  
        try{  
            stu = (Student)super.clone();   //浅复制 
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        stu.addr = (Address)addr.clone();   //深度复制 
        return stu;  
    }  
}  
public class Test { 
     

    public static void main(String args[]) {  

        Address addr = new Address();  
        addr.setAdd("杭州市");  
        Student stu1 = new Student();  
        stu1.setNumber(123);  
        stu1.setAddr(addr);  

        Student stu2 = (Student)stu1.clone();  

        System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());  
        System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());  

        addr.setAdd("西湖区");  

        System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());  
        System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());  
    }  
}

deep copy
这里写图片描述

在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。

简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。

在Java语言中,如果需要实现深克隆,可以通过覆盖Object类的clone()方法实现,也可以通过序列化(Serialization)等方式来实现。

(如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时我们可以用序列化的方式来实现对象的深克隆。)

序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。需要注意的是能够实现序列化的对象其类必须实现Serializable接口,否则无法实现序列化操作。

public class Outer implements Serializable{ 
   
  private static final long serialVersionUID = 369285298572941L;  //最好是显式声明ID
  public Inner inner;
 //Discription:[深度复制方法,需要对象及对象所有的对象属性都实现序列化] 
  public Outer myclone() {
      Outer outer = null;
      try { // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          ObjectOutputStream oos = new ObjectOutputStream(baos);
          oos.writeObject(this);
      // 将流序列化成对象
          ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
          ObjectInputStream ois = new ObjectInputStream(bais);
          outer = (Outer) ois.readObject();
      } catch (IOException e) {
          e.printStackTrace();
      } catch (ClassNotFoundException e) {
          e.printStackTrace();
      }
      return outer;
  }
}
public class Inner implements Serializable{ 
   
  private static final long serialVersionUID = 872390113109L; //最好是显式声明ID
  public String name = "";

  public Inner(String name) {
      this.name = name;
  }

  @Override
  public String toString() {
      return "Inner的name值为:" + name;
  }
}

参考资料:
https://www.cnblogs.com/Qian123/p/5710533.html#_label2

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/181879.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • [黑苹果系列] M910x完美黑苹果系统安装教程 – 2 制作系统U盘-USB Creation

    [黑苹果系列] M910x完美黑苹果系统安装教程 – 2 制作系统U盘-USB Creation目前主流的苹果系统的安装方法有两种:1.U盘安装2.Windows下使用镜像恢复软件安装的方式目前,U盘安装是主流选择,这样安装调试好的黑苹果macOS问题最少,也较为稳定。之前的文章由于采用的是镜像恢复的方法,此次安装采取U盘安装系统的方式,因此重新写一篇。1.前期准备U盘一个,大于16G 安装工具软件包 镜像文件 制作合适的EFI文件 需要准备40GB以上独立固态硬盘空间2.下载macOs镜像3.制作安装U盘可以用TransMac或者balenaEt.

    2022年6月9日
    93
  • springboot框架有哪些技术_Springboot常用注解

    springboot框架有哪些技术_Springboot常用注解✍、SpringBoot框架技术总结(一)1、SpringBoot简介我们之前的SSM还是使用起来不够爽。还需要写很多的配置才能进行正常的使用。实现一个功能需要引入很多的依赖,尤其是要自己去维护依赖的版本,特别容易出现依赖冲突等问题。SpringBoot就能很好的解决上述问题。中文文档:https://doc.springcloud.io/spring-boot/index.html1.1、SpringBoot是什么SpringBoot是基于Spring开发的全新框架,相当于对Spri

    2022年8月20日
    6
  • PyCharm 2022.01.13永久激活[最新免费获取]

    (PyCharm 2022.01.13永久激活)本文适用于JetBrains家族所有ide,包括IntelliJidea,phpstorm,webstorm,pycharm,datagrip等。https://javaforall.net/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~1…

    2022年3月31日
    113
  • Java面试之JDBC & Hibernate

    Java面试之JDBC & HibernateJava面试之JDBC & Hibernate

    2022年4月22日
    42
  • 1/7的小数点后2020位的数字是_九八K

    1/7的小数点后2020位的数字是_九八K给定长度为 N 的整数序列 A,下标为 1∼N。现在要执行 M 次操作,其中第 i 次操作为给出三个整数 li,ri,ki,求 A[li],A[li+1],…,A[ri] (即 A 的下标区间 [li,ri])中第 ki 小的数是多少。输入格式第一行包含两个整数 N 和 M。第二行包含 N 个整数,表示整数序列 A。接下来 M 行,每行包含三个整数 li,ri,ki,用以描述第 i 次操作。输出格式对于每次操作输出一个结果,表示在该次操作中,第 k 小的数的数值。每个结果占一行。数据范围

    2022年8月9日
    3
  • ts切片文件的合并

    ts切片文件的合并https://www.icourse163.org/中国大学MOOC的课程经历了几个变化:Adobe的FLASH格式(*.flv)逐渐替换为H5格式的(*.mp4),然后由于监管趋严,有些课程找不到了。比如我想下一期再看的《加密与解密》的课程就找不到了!使用方法一:ts视频合并工具(tsMergertools)v1.0.0….

    2022年4月3日
    40

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号