Java克隆(Clone)的应用
简介:
Java克隆(Clone)是Java语言的特性之一,但在实际中应用比较少见。但有时候用克隆会更方便更有效率。
对于克隆(Clone),Java有一些限制:
1、被克隆的类必须自己实现Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。Cloneable 接口实际上是个标识接口,没有任何接口方法。
2、实现Cloneable接口的类应该使用公共方法重写 Object.clone(它是受保护的)。某个对象实现了此接口就克隆它是不可能的。即使 clone 方法是反射性调用的,也无法保证它将获得成功。
3、在Java.lang.Object类中克隆方法是这么定义的:
protected Object clone()
throws CloneNotSupportedException
创建并返回此对象的一个副本。表明是一个受保护的方法,同一个包中可见。
按照惯例,返回的对象应该通过调用 super.clone 获得。
引题:
举个例子说吧,现在有一个对象比如叫foo,你需要在创建当前对象的一个副本作为存根你能怎么做?
假如你不用Clone,那么你可以先new一个对象foo1:Foo foo1=new Foo(),然后用foo给foo1对象set值,这样就得到foo的副本foo1;除此之外,别无选择。
这样说,也许有人会觉得说的过于绝对了,不过事实如此啊。
要产生一个副本,那副本要不要内存?----当然要了,那就对了!既然需要内存,(不克隆的情况下)你不new还有什么办法呢?请大家时刻铭记对象是Java运行时产生的,驻留在计算机内存中。
常见错误:
下面我澄清几个初学者容易犯迷糊的错误,同样的问题,产生foo对象的副本:
1、Foo foo1=new Foo();
foo1=foo;
然后就想当然的认为副本foo1生成了!
错误原因:foo1没错是申请了内存,但是执行foo1=foo后,foo1就不在指向刚申请的内存区域了,转而指向foo对象的内存区域,这时候,foo1、foo指向了同一内存区域。刚才new的操作制造一堆垃圾等着JVM回收。
2、Foo foo1=foo;
错误原因:还是两个变量都指向了同一块内存。
3、有些老鸟更厉害一些:在Foo中定义一个返回自身的方法:
public Foo getInstance(){
return this;
}
然后,Foo foo1=foo.getInstance();
错误原因:同上,主要还是没有重新开辟内存,this在对象里是什么?----就是对象自己的引用!那么getInstance()自然返回的就是对象自己,反正又是两个对象穿了一条裤子----***,哈哈。错得心服口服吧。为了节省篇幅,我在最后写个例子,留给那些对此有异议的人看。
引入克隆
看了这么多方法都不行,还很麻烦!干脆用克隆吧,简单明了。
废话不说了,看例子:
定义两个类CloneFooA、CloneFooB,然后写个测试类CloneDemo分别克隆这两个类的对象,然后打印测试结果到控制台。
/**
 * Created by IntelliJ IDEA.
 * User: leizhimin
 * Date: 2007-9-20
 * Time: 19:40:44
 * 简单类克隆实现
 * 要实现克隆,必须实现Cloneable接口,这是一个标识接口,没有接口方法
 * 实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。
 * 按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。
 */
public class CloneFooA implements Cloneable {
private String strA;
private int intA;
public CloneFooA(String strA, int intA) {
this.strA = strA;
this.intA = intA;
}
public String getStrA() {
return strA;
}
public void setStrA(String strA) {
this.strA = strA;
}
public int getIntA() {
return intA;
}
public void setIntA(int intA) {
this.intA = intA;
}
/**
* @return 创建并返回此对象的一个副本。
* @throws CloneNotSupportedException
*/
public Object clone() throws CloneNotSupportedException {
//直接调用父类的clone()方法,返回克隆副本
return super.clone();
}
}
/**
 * Created by IntelliJ IDEA.
 * User: leizhimin
 * Date: 2007-9-20
 * Time: 19:59:55
 * 深度克隆对象,当类存在聚合关系的时候,克隆就必须考虑聚合对象的克隆
 */
public class CloneFooB implements Cloneable {
private CloneFooA fooA;
private Double douB;
public CloneFooB(Double douB) {
this.douB = douB;
}
public CloneFooB(CloneFooA fooA, Double douB) {
this.fooA = fooA;
this.douB = douB;
}
public CloneFooA getFooA() {
return fooA;
}
public void setFooA(CloneFooA fooA) {
this.fooA = fooA;
}
public Double getDouB() {
return douB;
}
public void setDouB(Double douB) {
this.douB = douB;
}
    /**
     * 克隆操作
     *
     * @return 自身对象的一个副本
     * @throws CloneNotSupportedException
     */
public Object clone() throws CloneNotSupportedException {
//先调用父类的克隆方法进行克隆操作
CloneFooB cloneFooB = (CloneFooB) super.clone();
//对于克隆后出的对象cloneFooB,如果其成员fooA为null,则不能调用clone(),否则出空指针异常
if (this.fooA != null)
cloneFooB.fooA = (CloneFooA) this.fooA.clone();
return cloneFooB;
}
}
/**
 * Created by IntelliJ IDEA.
 * User: leizhimin
 * Date: 2007-9-20
 * Time: 19:52:01
 * 测试类:分别克隆CloneFooA和CloneFooB类,并打印克隆前后的结果.
 */
public class CloneDemo {
public static void main(String args[]) throws CloneNotSupportedException {
//CloneFooA克隆前
CloneFooA fooA1 = new CloneFooA("FooA", 11);
System.out.println("CloneFooA的对象克隆前对象fooA1值为: " + fooA1.getStrA() + "," + fooA1.getIntA());
//CloneFooA克隆后
CloneFooA fooA2 = (CloneFooA) fooA1.clone();
System.out.println("CloneFooA的对象克隆后对象fooA2值为: " + fooA2.getStrA() + "," + fooA2.getIntA());
//比较fooA1和fooA2内存地址
if (fooA1 == fooA2) System.out.println("比较fooA1和fooA2内存地址:相等!");
else System.out.println("比较fooA1和fooA2内存地址:不相等!");
System.out.println("-------------------------");
//CloneFooB克隆前
CloneFooB fooB1 = new CloneFooB(fooA1, new Double("33"));
System.out.println("CloneFooB的对象克隆前对象fooB1值为: " + fooB1.getFooA().getStrA() + "," + fooB1.getFooA().getIntA() + " | " + fooB1.getDouB());
//CloneFooB克隆后
CloneFooB fooB2 = (CloneFooB) fooB1.clone();
System.out.println("CloneFooB的对象克隆前对象fooB2值为: " + fooB2.getFooA().getStrA() + "," + fooB2.getFooA().getIntA() + " | " + fooB2.getDouB());
if (fooA1 == fooA2) System.out.println("比较fooB1和fooB2内存地址:相等!");
else System.out.println("比较fooB1和fooB2内存地址:不相等!");
}
}
运行结果:
CloneFooA的对象克隆前对象fooA1值为: FooA,11
CloneFooA的对象克隆后对象fooA2值为: FooA,11
比较fooA1和fooA2内存地址:不相等!
-------------------------
CloneFooB的对象克隆前对象fooB1值为: FooA,11 | 33.0
CloneFooB的对象克隆前对象fooB2值为: FooA,11 | 33.0
比较fooB1和fooB2内存地址:不相等!
Process finished with exit code 0
反面教材:
最后,我给出我上面提出到最后要给出的反面例子。
随便写一个,在CloneFooA 的基础上做了少许改动,内容如下:
public class CloneFooA implements Cloneable {
private String strA;
private int intA;
public CloneFooA(String strA, int intA) {
this.strA = strA;
this.intA = intA;
}
public String getStrA() {
return strA;
}
public void setStrA(String strA) {
this.strA = strA;
}
public int getIntA() {
return intA;
}
public void setIntA(int intA) {
this.intA = intA;
}
/**
* @return 创建并返回此对象的一个副本。
* @throws CloneNotSupportedException
*/
public Object clone() throws CloneNotSupportedException {
//直接调用父类的clone()方法,返回克隆副本
return super.clone();
}
    /**
     * @return 返回运行时的对象
     */

    public CloneFooA getInstance(){
        return this;
    }
public static void main(String args[]){
CloneFooA fooA=new CloneFooA("aa",11);
System.out.println(fooA.getStrA()+"  "+fooA.getIntA());
CloneFooA fooA1=fooA.getInstance();
System.out.println(fooA1.getStrA()+"  "+fooA1.getIntA());
if(fooA==fooA1) System.out.println("fooA和fooA1内存地址相等!");
System.out.println("-------------------------");
//改变后fooA或者fooA1中任何一个,看看另外一个是否会改变
fooA1.setStrA("bb");
System.out.println(fooA.getStrA()+"  "+fooA.getIntA());
System.out.println(fooA1.getStrA()+"  "+fooA1.getIntA());
if(fooA==fooA1) System.out.println("fooA和fooA1内存地址相等,改变fooA1后,fooA的值也跟着变化了");
}
}
运行结果:
aa  11
aa  11
fooA和fooA1内存地址相等!
-------------------------
bb  11
bb  11
fooA和fooA1内存地址相等,改变fooA1后,fooA的值也跟着变化了

转载于:https://blog.51cto.com/qiaofengzxq/688537

Java克隆(Clone)的应用相关推荐

  1. java中clone方法_Java Object clone()方法– Java中的克隆

    java中clone方法 Cloning is the process of creating a copy of an Object. Java Object class comes with na ...

  2. Java 对象的克隆Clone和必须了解的浅拷贝与深拷贝

    前言 为什么要写这篇文章? 因为我最近无意间看到了一些项目的代码,不管是曾经编码的人还是新接手的人, 在想完全克隆复制一个已经存在的对象,做为后续的使用,竟然都是采取了重写new一个,然后一个个属性字 ...

  3. java强克隆_java之克隆clone解密

    为了理解java的clone,有必要先温习以下的知识. java的类型,java的类型分为两大类,一类为primitive,如int,另一类为引用类型,如String,Object等等. java引用 ...

  4. 克隆clone() (Java)

    克隆clone() -> 使用clone()避免使用构造器生成对象. 重写clone()的原因: clone()本来的修饰符是protected,范围只是本类,本包和子类,范围不够大.在下面的例 ...

  5. Java设计模式百例(番外) - Java的clone

    本文源码见:https://github.com/get-set/get-designpatterns/tree/master/prototype 本文是为下一篇"Java设计模式百例 - ...

  6. java deep clone util_Java Clone深拷贝与浅拷贝的两种实现方法

    1.首先,你要知道怎么实现克隆:实现Cloneable接口,在bean里面重写clone()方法,权限为public. 2.其次,你要大概知道什么是地址传递,什么是值传递. 3.最后,你要知道你为什么 ...

  7. java 克隆有什么用_java中的克隆技术具体有什么应用?

    克隆(Clone),Java有一些限制: 1.被克隆的类必须自己实现Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制.Cloneable 接口实际 ...

  8. 解决克隆clone github 仓库速度过慢的问题

    解决克隆clone GitHub 仓库速度过慢的问题 由于大家都懂的原因,我们访问GitHub的速度确实有点慢,特别是克隆比较大的仓库的时候,那速度简直无法直视. 今天我就给大家带来一个邪门歪道,不通 ...

  9. 【DB宝35】使用MySQL 8.0 克隆(clone)插件快速添加MGR节点

    文章目录 一.MySQL 8.0.17的克隆clone简介 二.MGR现有环境 三.使用clone技术添加MGR节点 3.1 初始化新节点 3.2 新节点安装clone插件和组复制插件 3.3 新节点 ...

最新文章

  1. DevExpress.XtraGrid.GridControl中数据源的绑定问题
  2. CO模块之利润中心会计
  3. 买卖股票的最佳时机含手续费
  4. php设置路径别名,react设置文件路径别名的具体方法你知道么
  5. Python布局管理器
  6. element ui html编辑器,Vue + Element UI使用富文本编辑器
  7. 从内容/用户画像到如何做算法研发
  8. 绕障飞行器(D 题)--2020 年TI 杯大学生电子设计竞赛
  9. mnist数据集下载地址
  10. 黑客之门(hacker's door) 1.2 版
  11. 机器学习基础概念(三):归纳与演绎
  12. 淘宝app搜索排名优化技巧
  13. android系统可以识别NTFS格式吗,安卓手机支持ntfs格式的储存卡吗
  14. 怎么用ai做出适量插画_用AI打造矢量人像插画
  15. Linux文本三剑客(grep、sed、awk)
  16. MUI极简的JS函数
  17. L46.linux命令每日一练 -- 第七章 Linux用户管理及用户信息查询命令 -- w和who
  18. 跳槽时,这些Java面试题必须会,99%会被问到!
  19. Thunderbird配置Exchange邮箱
  20. Python中的 ctypes 的用法(byref)

热门文章

  1. 直接通过Binder的onTransact完成跨进程通信
  2. 乐视美国官网下线,官方公告称一周后还会回来
  3. 国内maven库镜像(阿里云)
  4. 可想实现一个自己的简单jQuery库?(五)
  5. 在Linux下安装RabbitMQ
  6. mysql 5.1 禁用innodb
  7. c#.net URL参数传递及在js中引用
  8. 为SharePoint 2010创建Application Page
  9. sudo 密码超时时间
  10. WebLogic集群案例分析