伙伴云客服论坛»论坛 S区 S软件开发 查看内容

0 评论

0 收藏

分享

Java Cloneable接口的深拷贝与浅拷贝详解

目录

    Cloneable接口源码浅拷贝案例
      Pet类定义Person类定义浅拷贝问题-代码测试
    深拷贝案例
      Pet类重写clone()方法Person的clone()方法中调用Pet的clone方法浅拷贝问题处置-深拷贝代码测试
    总结


Cloneable接口源码

Cloneable接口:
实现此接口的类——可被推断java.lang.Object的clone()方法可以被合法调用-以实现类实例:属性到属性的拷贝。
假设一个类未实现Cloneable接口,那么调用clone()方法时,会抛出CloneNotSupportedException异常。
通常,实现了Cloneable接口的子类,应当以public访问权限重写clone()方法(虽然java.Object类中的clone方法是protected类型的)
应当认识到:Cloneable接口没有包含clone()方法,因而,假设仅仅是implements了Cloneable接口,那么也是无法正常克隆对象的
[原因:即便是反射性地调用了克隆方法,也不能保证它一定会胜利]——个人理解就是:是否重写Clone()方法、或者“浅拷贝与深拷贝”问题的存在所导致的。
  1. class Pet implements Cloneable{
  2.     //properties
  3.     private String name;
  4.     public void setName(String name) {
  5.         this.name = name;
  6.     }
  7.     public String getName() {
  8.         return name;
  9.     }
  10.     public Pet() {
  11.     }
  12.     public Pet(String name) {
  13.         this.name = name;
  14.     }
  15.     @Override
  16.     public String toString() {
  17.         return "Pet{" +
  18.                 "name='" + name + '\'' +
  19.                 '}';
  20.     }
  21.     @Override
  22.     public boolean equals(Object o) {
  23.         if (this == o) return true;
  24.         if (o == null || getClass() != o.getClass()) return false;
  25.         Pet pet = (Pet) o;
  26.         return Objects.equals(name, pet.name);
  27.     }
  28.     @Override
  29.     public int hashCode() {
  30.         return Objects.hash(name);
  31.     }
  32. //    @Override
  33. //    public Pet clone() {
  34. //        try {
  35. //            return (Pet)super.clone();
  36. //        } catch (CloneNotSupportedException e) {
  37. //            e.printStackTrace();
  38. //        }
  39. //        return null;
  40. //    }
  41. }
复制代码
浅拷贝案例


Pet类定义

注意到:Pet类实现了Cloneable接口,但是没有重写Clone()方法(显然:此时Pet类不具备对象克隆的才干)。
  1. class Pet implements Cloneable{
  2.     //properties
  3.     private String name;
  4.     public void setName(String name) {
  5.         this.name = name;
  6.     }
  7.     public String getName() {
  8.         return name;
  9.     }
  10.     public Pet() {
  11.     }
  12.     public Pet(String name) {
  13.         this.name = name;
  14.     }
  15.     @Override
  16.     public String toString() {
  17.         return "Pet{" +
  18.                 "name='" + name + '\'' +
  19.                 '}';
  20.     }
  21.     @Override
  22.     public boolean equals(Object o) {
  23.         if (this == o) return true;
  24.         if (o == null || getClass() != o.getClass()) return false;
  25.         Pet pet = (Pet) o;
  26.         return Objects.equals(name, pet.name);
  27.     }
  28.     @Override
  29.     public int hashCode() {
  30.         return Objects.hash(name);
  31.     }
  32. //    @Override
  33. //    public Pet clone() {
  34. //        try {
  35. //            return (Pet)super.clone();
  36. //        } catch (CloneNotSupportedException e) {
  37. //            e.printStackTrace();
  38. //        }
  39. //        return null;
  40. //    }
  41. }
复制代码
Person类定义

注意到:Person类实现了Cloneable接口,也重写Clone()方法。那么,是否Person类就具备了对象克隆的才干呢?(由于浅拷贝问题的存在,认为这种对象克隆才干是不完好的、有缺陷的)。
  1. class Pet implements Cloneable{
  2.     //properties
  3.     private String name;
  4.     public void setName(String name) {
  5.         this.name = name;
  6.     }
  7.     public String getName() {
  8.         return name;
  9.     }
  10.     public Pet() {
  11.     }
  12.     public Pet(String name) {
  13.         this.name = name;
  14.     }
  15.     @Override
  16.     public String toString() {
  17.         return "Pet{" +
  18.                 "name='" + name + '\'' +
  19.                 '}';
  20.     }
  21.     @Override
  22.     public boolean equals(Object o) {
  23.         if (this == o) return true;
  24.         if (o == null || getClass() != o.getClass()) return false;
  25.         Pet pet = (Pet) o;
  26.         return Objects.equals(name, pet.name);
  27.     }
  28.     @Override
  29.     public int hashCode() {
  30.         return Objects.hash(name);
  31.     }
  32. //    @Override
  33. //    public Pet clone() {
  34. //        try {
  35. //            return (Pet)super.clone();
  36. //        } catch (CloneNotSupportedException e) {
  37. //            e.printStackTrace();
  38. //        }
  39. //        return null;
  40. //    }
  41. }
复制代码
浅拷贝问题-代码测试

为什么说:此时Person类的对象克隆才干是不完好的、有缺陷的?因为此时,在通过Person对象调用clone()方法,克隆对象时,其成员属性pet(Pet类的对象)值的克隆,仅仅是对堆区内存地址的简单拷贝。
即:说白了,Person对象和克隆出来的对象,其pet属性值共享同一块堆区内存。——问题显而易见:当对克隆出来的对象的pet属性停止set操作时,显然会影响到原始Person对象的pet属性值。
代码演示如下:
  1.   //methods
  2.     public static void main(String[] args) throws CloneNotSupportedException {
  3.         testPerson();
  4.     }
  5.     public static void testPerson() throws CloneNotSupportedException {
  6.         Person p=new Person("张三",14,new Pet("小黑"));
  7.         System.out.println(p);
  8.         Person clone = (Person)p.clone();
  9.         System.out.println(clone);
  10.         System.out.println(p.equals(clone));
  11.         System.out.println(p.getPet()==clone.getPet());
  12.         System.out.println("************");
  13.         clone.setAge(15);
  14.         System.out.println(p);
  15.         System.out.println(clone);
  16.         System.out.println(p.equals(clone));
  17.         System.out.println("************");
  18.         clone.getPet().setName("小黄");
  19.         System.out.println(p);
  20.         System.out.println(clone);
  21.         System.out.println(p.equals(clone));
  22.         System.out.println(p.getPet()==clone.getPet());
  23.     }
复制代码
Java Cloneable接口的深拷贝与浅拷贝详解-1.png


深拷贝案例

那么,如何实现深拷贝呢?关键就在上述案例中,被注释的几行代码中。

Pet类重写clone()方法

Java Cloneable接口的深拷贝与浅拷贝详解-2.png


Person的clone()方法中调用Pet的clone方法

Java Cloneable接口的深拷贝与浅拷贝详解-3.png


浅拷贝问题处置-深拷贝代码测试

测试代码不变,再次运行:
Java Cloneable接口的深拷贝与浅拷贝详解-4.png


总结

本篇文章就到这里了,希望可以给你带来协助,也希望您可以多多关注网站的更多内容!

回复

举报 使用道具

相关帖子
全部回复
暂无回帖,快来参与回复吧
本版积分规则 高级模式
B Color Image Link Quote Code Smilies

伙伴的小伙伴
注册会员
主题 16
回复 21
粉丝 0
|网站地图
快速回复 返回顶部 返回列表