cloneable方法

图标

豆瓜

豆瓜网

豆瓜网专栏

首发
豆瓜 图标 2020-10-17 00:59:48

1、使用



创建对象有两种方式: new 和 clone

当一个对象创建过程复杂,我们是否可以根据已有的对象直接来克隆一份,而不必关系创建的细节呢(原型模式)。

1.1 Java Object根类默认提供了clone方法:

[size=1em]

protected native Object clone() throws CloneNotSupportedException;

一个本地方法,protected权限: 这样做是为避免我们创建每一个类都默认具有克隆能力  


1.2 实现Cloneable接口

我们要使用一个对象的clone方法,必须Cloneable接口,这个接口没有任何实现,跟 Serializable一样是一种标志性接口

如果不实现Cloneable接口,会抛出CloneNotSupportedException异常

重写clone方法,使用public修饰(否则外部调用不到),调用父类的clone方法

如下:

[url=]

[/url]
public class CloneModel implements  Cloneable{    private String name;    private int age;    @Override    public Object clone() throws CloneNotSupportedException {        return super.clone();    }    @Override    public String toString() {        return "CloneModel{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }}[url=]

[/url]


1.3、Object.clone() 与 构造方法

我们看一个例子:

CloneModel类:

[url=]

[/url]
public class CloneModel implements  Cloneable{    private String name;    private int age;    public CloneModel(){        System.out.println("will new a instance");    }    @Override    public Object clone() throws CloneNotSupportedException {        return super.clone();    }    @Override    public String toString() {        return "CloneModel{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }}[url=]

[/url]

当我们调用此对象的clone方法时,构造方法并没有被调用,所以我说创建一个对象new和clone是两条路

[size=1em]

public static void main(String[] args) throws CloneNotSupportedException {
        CloneModel cloneModel = new CloneModel();
        System.out.println(cloneModel.clone());
    }

打印:

CloneModel{name='null', age=0}


2、重写clone方法原则



x.clone != x将会是true;

x.clone().getClass()==x.getClass()将会是true(不是绝对的,但建议这么做)

x.clone().equals(x)将会是true(不是绝对的,但建议这么做)


3、浅克隆和深克隆



3.1 默认clone方法时浅克隆

Object默认的clone方法实际是对域的简单拷贝,对于简单数据类型,是值的拷贝;

对于复杂类型的字段,则是指针地址的拷贝,clone后的对象和原对象指向的还是一个地址空间

所以说默认的clone方法时浅克隆。

例子:

 View Code

clone之后比较复杂对象是否相等

[size=1em]

public static void main(String[] args) throws CloneNotSupportedException {
        CloneModel cloneModel1 = new CloneModel();
        CloneModel cloneModel2 = (CloneModel)cloneModel1.clone();
        System.out.println(cloneModel1.getModel2()==cloneModel2.getModel2());
    }


执行返回:true


3.2 如何实现深克隆

还是上面的例子,我们改下代码

 View Code

再次测试下:

[size=1em]

public static void main(String[] args) throws CloneNotSupportedException {
        CloneModel cloneModel1 = new CloneModel();
        CloneModel cloneModel2 = cloneModel1.clone();
        System.out.println(cloneModel1.getModel2()==cloneModel2.getModel2());
    }

执行返回:false

这么做就要在super.clone的基础上 继续对非基本类型的对象递归的再次clone.

显然这么方式是繁琐的且不可靠的。

有没有其他的方式呢?有 序列化


3.3 序列化实现深度克隆

(1) 使用java自身的序列化转为二进制数 ,再反序列化为对象

上面的例子改造下

 View Code


测试代码:

 View Code

测试输出:false


(2)其他序列化方式,如对象序列化json字符串再反序列化为对象

我们使用google的gson来进行序列化,上代码

 View Code

测试代码:

[size=1em]

public static void main(String[] args) throws IOException {
        CloneModel cloneModel1 = new CloneModel();
        CloneModel cloneModel2 = cloneModel1.deepClone();
        System.out.println(cloneModel1.getModel2()==cloneModel2.getModel2());
    }

执行返回:false


性能对比测试:

上代码:

[size=1em]

public static void main(String[] args) throws IOException {
        CloneModel cloneModel1 = new CloneModel();
        long time1 = System.currentTimeMillis();
        for(int i=0;i<1000;i++){
//            CloneModel cloneModel2 = cloneModel1.deepClone();
            CloneModel cloneModel2 = deepCloneObject(cloneModel1);
        }
        long time2 = System.currentTimeMillis();
        System.out.println((time2-time1)+"ms");
    }


循环1000次

Serializable耗时:118ms

json耗时:167ms

对比Serializablegson
易用性对象要实现Serializable,依赖的子元素依然要实现此接口,不易扩展无要求,额外的工具控制,易用使用
性能对比1000次clone耗时118ms,稍好1000次clone耗时


本文由豆瓜网专栏作家 豆瓜 投稿发布,并经过豆瓜网编辑审核。

转载此文章须经作者同意,并附上出处(豆瓜网)及本页链接。

若稿件文字、图片、视频等内容侵犯了您的权益,请联系本站进行 投诉处理

相关搜索

cloneable
图标 图标

豆瓜

豆瓜网

豆瓜网专栏

  • cloneable方法

    图标
    豆瓜 图标 · 今天 00:59:48 · 0浏览
  • response.setheader怎么使用

    图标
    豆瓜 图标 · 今天 00:53:33 · 7浏览
  • ipage分页功能说明

    图标
    豆瓜 图标 · 今天 00:52:20 · 10浏览
  • 全部评论

    豆瓜

    豆瓜网

    豆瓜网专栏

  • cloneable方法
  • response.setheader怎么使用
  • ipage分页功能说明
  • java下载文件功能怎么实现
  • 正则表达式 数字的表达式
  • 我来说两句