Java clone

来源:互联网 发布:淘宝网自助开通在哪里 编辑:程序博客网 时间:2024/06/04 01:17

参考:

java.lang Interface Cloneable

java.lang Class Object


下面学习 Java 中的 Object.clone() 方法 和 cloneable 接口的概念和使用,学习关于 强复制(克隆,拷贝)和浅复制 的区别和联系


主要内容:

  1. Object.clone() 方法和 cloneable 接口
  2. Object.clone() 方法的实现
  3. 深复制和浅复制

Object.clone() 方法和 cloneable 接口

参考:java.lang Class Object

Object.clone() 方法

Object 类是 Java 中类层次结构的根,是所有类的超类。新建一个类,如果没有继承超类,Java 默认使用 Object 类作为该类的超类

Object.clone() 方法格式如下:

protected native Object clone() throws CloneNotSupportedException;

功能:创建并返回复制对象

Cloneable 接口

Cloneable 接口没有任何方法,它仅用于表明类想要重载 Object.clone() 方法。如果没有继承该接口就重载 Object.clone() 方法,Object.clone() 方法将抛出 java.lang.CloneNotSupportedException 异常


Object.clone() 方法的实现

创建新类 Cloner,继承接口 Cloneable,并重载 clone 方法

import java.util.Arrays;/** * Created by zj on 2017/10/16. */public class Cloner implements Cloneable {    private int num;    private String str;    private Person person;    public Cloner(int num, String str, Person person) {        this.num = num;        this.str = str;        this.person = person;    }    public void setNum(int num) {        this.num = num;    }    public void setStr(String str) {        this.str = str;    }    public void setName(String name) {        this.person.setName(name);    }    public void setAge(int age) {        this.person.setAge(age);    }    @Override    public String toString() {        return "Cloner{" +                "num=" + num +                ", str='" + str + '\'' +                ", person=" + person +                '}';    }    //    @Override//    protected Object clone() throws CloneNotSupportedException {//        return super.clone();//    }    @Override    protected Object clone() {        Cloner cloner = null;        try {            cloner = (Cloner) super.clone();        } catch (CloneNotSupportedException e) {            e.printStackTrace();        }        return cloner;    }    static class Person {        String name;        int age;        public Person(String name, int age) {            this.name = name;            this.age = age;        }        public void setName(String name) {            this.name = name;        }        public void setAge(int age) {            this.age = age;        }        @Override        public String toString() {            return "Person{" +                    "name='" + name + '\'' +                    ", age=" + age +                    '}';        }    }}

重载方法 clone(),调用超类的 clone() 方法即可实现对象复制,因为 clone() 方法会抛出检查时异常 CloneNotSupportedException,所以修改代码如上所示

测试代码如下:

    public static void main(String[] args) throws CloneNotSupportedException {        int num = 10;        String str = "str";        Person person = new Person("zj", 1111);        Cloner src = new Cloner(10, "str", person);        Cloner dst = (Cloner) src.clone();        System.out.println("Before...");        System.out.println(src);        System.out.println(dst);        dst.setNum(20);        dst.setStr("str2");        dst.setName("name");        dst.setAge(100);        System.out.println("After...");        System.out.println(src);        System.out.println(dst);    }

这里写图片描述

问题:创建一个类 Cloner 的实例 src,并得到它的克隆对象 dst,修改 dst 的值,发现 src 的部分属性也发生了变化


深复制和浅复制

参考:

java clone()机制

使用 clone() 方法进行对象的复制,就是在堆上新建一个和原先对象同样大小的存储空间,将原先对象的内容复制到该存储空间

优点如下:

  1. 操作简单:仅需重载 clone() 方法即可
  2. 执行效率高:如果使用 new 关键字重新建一个对象,然后进行属性的复制,需要耗费大量的操作

缺点如下:

如果仅执行 super.clone() 方法进行复制,对复制对象的操作有可能会改变原先对象的属性

原始类型(primitive type)

参考:

Java的原始类型(Primitive Type)

Java 的原始类型就是指基本数据类型,即

  • byte
  • char
  • short
  • int
  • long
  • float
  • double
  • boolean

可变(mutable),不可变(immutable)对象

参考:

如何创建不可变(Immutable)的Java类或对象

Java中mutable对象和immutable对象的区别

不可变对象指对象被创建后无法改变状态的对象,即每次对它进行操作都是产生了新的对象,如 String

而可变对象与之相反,对象在创建后,可以在本身发送改变,如 StringBuffer

浅复制

直接使用 Object.clone() 方法进行复制的操作属于浅复制

即如果该对象内部包含了对可变对象的引用,那么复制得到的新对象同样拥有对该可变对象的引用,所以在新对象中进行可变对象的操作后,原对象的属性也发生了变化

深复制

如果复制得到的对象的操作不会影响到原对象,那么这种操作就是深复制

为实现深复制,需要在重载 clone() 方法的时候对可变对象创建新的地址空间,

上面代码修改如下:

@Overrideprotected Object clone() {    Cloner cloner = null;    try {        cloner = (Cloner) super.clone();        cloner.person = new Person(this.person.name, this.person.age);    } catch (CloneNotSupportedException e) {        e.printStackTrace();    }    return cloner;}

重新测试,结果如下:

这里写图片描述

原创粉丝点击