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

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

发表回复

您的电子邮箱地址不会被公开。

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