文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java中的clone()和Cloneable接口使用方法是什么

2023-06-25 12:54

关注

本篇内容介绍了“Java中的clone()和Cloneable接口使用方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

clone()和Cloneable接口

clone顾名思义就是克隆,即,复制一个相等的对象,但是不同的引用地址。

我们知道拿到一个对象的地址,只要提供相应的方法就可以修改这个对象,但是如果我们想要得到这个对象去修改它,又想保留这个对象原来的属性,这是就可以使用clone(),它会复制一个内容相同的对象而具有不同内存地址。

Cloneable接口,就是我们要使用clone()必须实现的接口,不然会抛出异常。

public class Bean implements Cloneable {    private String a;     public Bean(String a) {        this.a = a;    }     public String getA() {        return a;    }     @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }     @Override    public boolean equals(Object o) {        if(o instanceof Bean){            Bean bean = (Bean) o;            return bean.getA().equals(a);        }        return false;    }}

在Cloneable 接口中并没有给我们定义任何方法

这里需要重写clone()方法

protected native Object clone() throws CloneNotSupportedException;protected Object clone() throws CloneNotSupportedException {        if (!(this instanceof Cloneable)) {            throw new CloneNotSupportedException("Class " + getClass().getName() +                                                 " doesn't implement Cloneable");        }         return internalClone();    }

它是Object类里面的native方法,它是protected的,根据需要可以写为public,可以看到如果不实现Cloneable接口将会抛出CloneNotSupportedException 异常。

测试一下

try {             Bean a = new Bean("lzy");            Bean b = a;            Bean c = (Bean) a.clone();             Log.i(TAG, "onCreate: " + (a == b));         //true            Log.i(TAG, "onCreate: " + (a.equals(b)));    //true             Log.i(TAG, "onCreate: " + (a == c));         //false            Log.i(TAG, "onCreate: " + (a.equals(c)));    //true          } catch (CloneNotSupportedException e) {            e.printStackTrace();        }

可以看到克隆出来的类的地址是不同的,而内容是相同的。

下面修改一下,在Bean加一个成员变量ChildBean

public class ChildBean implements Cloneable {    private String c;    public String getC() {        return c;    }    public ChildBean(String c) {        this.c = c;    }    @Override    public Object clone() throws CloneNotSupportedException {        return super.clone();    }    @Override    public boolean equals(Object o) {        if (o instanceof ChildBean) {            ChildBean bean = (ChildBean) o;            return bean.getC().equals(c);        }        return false;    }}
public class Bean implements Cloneable {    private String a;    private ChildBean childBean;     public Bean(String a, ChildBean childBean) {        this.a = a;        this.childBean = childBean;    }    public String getA() {        return a;    }     public ChildBean getChildBean() {        return childBean;    }     @Override    public Object clone() throws CloneNotSupportedException {        return super.clone();    }     @Override    public boolean equals(Object o) {        if (o instanceof Bean) {            Bean bean = (Bean) o;            return bean.getA().equals(a);        }        return false;    }}
Bean a = new Bean("lzy", new ChildBean("child"));            Bean b = a;            Bean c = (Bean) a.clone();             Log.i(TAG, "onCreate: " + (a.getChildBean() == b.getChildBean()));         //true            Log.i(TAG, "onCreate: " + (a.getChildBean().equals(b.getChildBean())));    //true             Log.i(TAG, "onCreate: " + (a.getChildBean() == c.getChildBean()));         //true            Log.i(TAG, "onCreate: " + (a.getChildBean().equals(c.getChildBean())));    //true

测试发现有一个结果不是我们所预期的,这意味着并没有真正克隆ChildBean,只是克隆的它的内存地址,导致两个具有相同的内存地址,这也就是浅克隆,此时我们需要的是深克隆,需要按照下面方法修改,重写clone()方法

  @Override    public Object clone() throws CloneNotSupportedException {        Bean bean = (Bean) super.clone();        bean.childBean = (ChildBean) bean.childBean.clone();        return bean;    }

但是这样做如果有很多层的类,那每一层都需要去重写,显得很麻烦。所以我们可以用下面的工具类来实现

public class BeanUtil {    public static <T> T cloneTo(T src) throws RuntimeException {        ByteArrayOutputStream memoryBuffer = new ByteArrayOutputStream();        ObjectOutputStream out = null;        ObjectInputStream in = null;        T dist = null;        try {            out = new ObjectOutputStream(memoryBuffer);            out.writeObject(src);            out.flush();            in = new ObjectInputStream(new ByteArrayInputStream(memoryBuffer.toByteArray()));            dist = (T) in.readObject();        } catch (Exception e) {            throw new RuntimeException(e);        } finally {            if (out != null)                try {                    out.close();                    out = null;                } catch (IOException e) {                    throw new RuntimeException(e);                }            if (in != null)                try {                    in.close();                    in = null;                } catch (IOException e) {                    throw new RuntimeException(e);                }        }        return dist;    }}
Bean a = new Bean("lzy", new ChildBean("child"));        Bean b = BeanUtil.cloneTo(a);         Log.i(TAG, "onCreate: " + (a.getChildBean() == b.getChildBean()));         //false        Log.i(TAG, "onCreate: " + (a.getChildBean().equals(b.getChildBean())));    //true

这样就可以很轻松的得到我们预期的结果,但是记得每一个类都要去 实现Serializable接口。

Cloneable和clone()的总结

1.Cloneable 的用途

Cloneable和Serializable一样都是标记型接口,它们内部都没有方法和属性,implements Cloneable表示该对象能被克隆,能使用Object.clone()方法。如果没有implements Cloneable的类调用Object.clone()方法就会抛出CloneNotSupportedException。

2.克隆的分类

(1)浅克隆(shallow clone),浅拷贝是指拷贝对象时仅仅拷贝对象本身和对象中的基本变量,而不拷贝对象包含的引用指向的对象。

(2)深克隆(deep clone),深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。

举例区别一下:对象A1中包含对B1的引用,B1中包含对C1的引用。浅拷贝A1得到A2,A2中依然包含对B1的引用,B1中依然包含对C1的引用。深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2中包含对C2(C1的copy)的引用。

3.克隆的举例

要让一个对象进行克隆,其实就是两个步骤:

让该类实现java.lang.Cloneable接口;

重写(override)Object类的clone()方法。

public class Wife implements Cloneable {      private int id;      private String name;      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 Wife(int id,String name) {          this.id = id;          this.name = name;      }      @Override      public int hashCode() {//myeclipse自动生成的          final int prime = 31;          int result = 1;          result = prime * result + id;          result = prime * result + ((name == null) ? 0 : name.hashCode());          return result;      }      @Override      public boolean equals(Object obj) {//myeclipse自动生成的          if (this == obj)              return true;          if (obj == null)              return false;          if (getClass() != obj.getClass())              return false;          Wife other = (Wife) obj;          if (id != other.id)              return false;          if (name == null) {              if (other.name != null)                  return false;          } else if (!name.equals(other.name))              return false;          return true;      }      @Override      public Object clone() throws CloneNotSupportedException {          return super.clone();      }            public static void main(String[] args) throws CloneNotSupportedException {          Wife wife = new Wife(1,"wang");          Wife wife2 = null;          wife2 = (Wife) wife.clone();          System.out.println("class same="+(wife.getClass()==wife2.getClass()));//true          System.out.println("object same="+(wife==wife2));//false          System.out.println("object equals="+(wife.equals(wife2)));//true      }  }

4.浅克隆的举例

public class Husband implements Cloneable {      private int id;      private Wife wife;      public Wife getWife() {          return wife;      }      public void setWife(Wife wife) {          this.wife = wife;      }      public int getId() {          return id;      }      public void setId(int id) {          this.id = id;      }      public Husband(int id) {          this.id = id;      }      @Override      public int hashCode() {//myeclipse自动生成的          final int prime = 31;          int result = 1;          result = prime * result + id;          return result;      }      @Override      protected Object clone() throws CloneNotSupportedException {          return super.clone();      }      @Override      public boolean equals(Object obj) {//myeclipse自动生成的          if (this == obj)              return true;          if (obj == null)              return false;          if (getClass() != obj.getClass())              return false;          Husband other = (Husband) obj;          if (id != other.id)              return false;          return true;      }            public static void main(String[] args) throws CloneNotSupportedException {          Wife wife = new Wife(1,"jin");          Husband husband = new Husband(1);          Husband husband2 = null;          husband.setWife(wife);          husband2 = (Husband) husband.clone();          System.out.println("husband class same="+(husband.getClass()==husband2.getClass()));//true          System.out.println("husband object same="+(husband==husband2));//false          System.out.println("husband object equals="+(husband.equals(husband)));//true          System.out.println("wife class same="+(husband.getWife().getClass()==husband2.getWife().getClass()));//true          System.out.println("wife object same="+(husband.getWife()==husband2.getWife()));//true          System.out.println("wife object equals="+(husband.getWife().equals(husband.getWife())));//true      }  }

5.深克隆的举例

如果要深克隆,需要重写(override)Object类的clone()方法,并且在方法内部调用持有对象的clone()方法;注意如下代码的clone()方法

public class Husband implements Cloneable {      private int id;      private Wife wife;      public Wife getWife() {          return wife;      }      public void setWife(Wife wife) {          this.wife = wife;      }      public int getId() {          return id;      }      public void setId(int id) {          this.id = id;      }      public Husband(int id) {          this.id = id;      }      @Override      public int hashCode() {//myeclipse自动生成的          final int prime = 31;          int result = 1;          result = prime * result + id;          return result;      }      @Override      protected Object clone() throws CloneNotSupportedException {          Husband husband = (Husband) super.clone();          husband.wife = (Wife) husband.getWife().clone();          return husband;      }      @Override      public boolean equals(Object obj) {//myeclipse自动生成的          if (this == obj)              return true;          if (obj == null)              return false;          if (getClass() != obj.getClass())              return false;          Husband other = (Husband) obj;          if (id != other.id)              return false;          return true;      }            public static void main(String[] args) throws CloneNotSupportedException {          Wife wife = new Wife(1,"jin");          Husband husband = new Husband(1);          Husband husband2 = null;          husband.setWife(wife);          husband2 = (Husband) husband.clone();          System.out.println("husband class same="+(husband.getClass()==husband2.getClass()));//true          System.out.println("husband object same="+(husband==husband2));//false          System.out.println("husband object equals="+(husband.equals(husband)));//true          System.out.println("wife class same="+(husband.getWife().getClass()==husband2.getWife().getClass()));//true          System.out.println("wife object same="+(husband.getWife()==husband2.getWife()));//false          System.out.println("wife object equals="+(husband.getWife().equals(husband.getWife())));//true      }  }

但是也有不足之处,如果Husband内有N个对象属性,突然改变了类的结构,还要重新修改clone()方法。

解决办法:可以使用Serializable运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。

“Java中的clone()和Cloneable接口使用方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯