Java中对象的创建

clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象。

所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象。那么在java语言中,有几种方式可以创建对象呢?

  ⊙ 使用new操作符创建一个对象

  ⊙ 使用clone方法复制一个对象

那么这两种方式有什么相同和不同呢?

new操作符的本意是分配内存。程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。

clone在第一步是和new相似的, 都是分配内存,调用clone方法时,分配的内存和源对象(即调用clone方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域, 填充完成之后,clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。

复制对象 or 复制引用

引用的复制

  Class : 引用的复制

package com.xindatai.ibs.lime;

import com.xindatai.ibs.lime.Person;

public class Lime {

    public static void main(String[] args) {
Person tom = new Person();
Person kit = tom;
System.out.println(tom);
System.out.println(kit);
}
}

当Person kit = tom;执行之后, 是创建了一个新的对象吗? 首先看打印结果:

com.xindatai.ibs.liang.Person@2f327c02
com.xindatai.ibs.liang.Person@2f327c02

可已看出,打印的地址值是相同的,既然地址都是相同的,那么肯定是同一个对象。p和p1只是引用而已,他们都指向了一个相同的对象Person() 。 可以把这种现象叫做引用的复制。上面代码执行完成之后, 内存中的情景如下图所示:

克隆

Class : 克隆

package com.xindatai.ibs.lime;

public class Person implements Cloneable{

    @Override
protected Person clone() {
Person per = null;
try {
per = (Person)super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return per;
}
}

Class :

package com.xindatai.ibs.lime;

import com.xindatai.ibs.lime.Person;

public class Lime {

    public static void main(String[] args) {

        Person tom = new Person();
Person kit = tom.clone();
System.out.println(tom);
System.out.println(kit);
}
}

Console :

com.xindatai.ibs.lime.Person@6bcf8de2
com.xindatai.ibs.lime.Person@76c27ba

从打印结果可以看出,两个对象的地址是不同的,也就是说创建了新的对象, 而不是把原对象的地址赋给了一个新的引用变量。

以上代码执行完成后, 内存中的情景如下图所示:

浅拷贝

由于age是基本数据类型, 那么对它的拷贝没有什么疑议,直接将一个4字节的整数值拷贝过来就行。但是name是String类型的, 它只是一个引用, 指向一个真正的String对象,那么对它的拷贝有两种方式: 直接将源对象中的name的引用值拷贝给新对象的name字段, 或者是根据原Person对象中的name指向的字符串对象创建一个新的相同的字符串对象,将这个新字符串对象的引用赋给新拷贝的Person对象的name字段。这两种拷贝方式分别叫做浅拷贝和深拷贝。深拷贝和浅拷贝的原理如下图所示:

下面通过代码进行验证。如果两个Person对象的name的地址值相同, 说明两个对象的name都指向同一个String对象, 也就是浅拷贝, 而如果两个对象的name的地址值不同, 那么就说明指向不同的String对象, 也就是在拷贝Person对象的时候, 同时拷贝了name引用的String对象, 也就是深拷贝。验证代码如下:

Class :Child

package com.xindatai.ibs.lime;

public class Child{

}

Class : Person

package com.xindatai.ibs.lime;

public class Person implements Cloneable{

    public String name;
public int age;
public Child child;
public Person() {
super();
}
public Person(String name, int age,Child child) {
this.name = name;
this.age = age;
this.child = child;
}
@Override
protected Person clone() {
Person per = null;
try {
per = (Person)super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return per;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} }

Class :

package com.xindatai.ibs.lime;

public class Lime {

    public static void main(String[] args) {

        Person tom = new Person("lime",23,new Child());
Person kit = tom.clone();
kit.name = "oracle";
System.out.println("tom.name : " + tom.name.hashCode() + "\n" + "tom.age : " + tom.age + "\n" + "tom.child : " + tom.child.hashCode());
System.out.println("kit.name : " + kit.name.hashCode() + "\n" + "kit.age : " + kit.age + "\n" + "kit.child : " + kit.child.hashCode());
}
}

Console :

tom.name : 3321813
tom.age : 23
tom.child : 1298693581
kit.name : -1008861826
kit.age : 23
kit.child : 1298693581

所以,clone方法执行的是浅拷贝, 在编写程序时要注意这个细节。

深拷贝

覆盖Object中的clone方法, 实现深拷贝

现在为了要在clone对象时进行深拷贝, 那么就要Clonable接口,覆盖并实现clone方法,除了调用父类中的clone方法得到新的对象, 还要将该类中的引用变量也clone出来。如果只是用Object中默认的clone方法,是浅拷贝的,再次以下面的代码验证:

Class : Child

package com.xindatai.ibs.lime;

public class Child implements Cloneable {

    @Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

Class : Person

package com.xindatai.ibs.lime;

public class Person implements Cloneable{

    public String name;
public int age;
public Child child;
public Person() {
super();
}
public Person(String name, int age,Child child) {
this.name = name;
this.age = age;
this.child = child;
}
@Override
protected Person clone() {
Person per = null;
try {
per = (Person)super.clone();
per.child = (Child) child.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return per;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} }

Class :

package com.xindatai.ibs.lime;

public class Lime {

    public static void main(String[] args) {

        Person tom = new Person("lime",23,new Child());
Person kit = tom.clone();
kit.name = "oracle";
System.out.println("tom.name : " + tom.name.hashCode() + "\n" + "tom.age : " + tom.age + "\n" + "tom.child : " + tom.child.hashCode());
System.out.println("kit.name : " + kit.name.hashCode() + "\n" + "kit.age : " + kit.age + "\n" + "kit.child : " + kit.child.hashCode());
}
}

Console :

tom.name : 3321813
tom.age : 23
tom.child : 119227759
kit.name : -1008861826
kit.age : 23
kit.child : 258702862

至于彻底深拷贝,几乎是不可能实现的

啦啦啦

对象克隆技术Object.clone()的更多相关文章

  1. 【java】对象克隆protected Object clone() throws CloneNotSupportedException

    package 对象克隆; class A implements Cloneable{//要具备clone()功能必须要实现Cloneable接口,此接口里无方法,只起标识作用. private St ...

  2. 吴裕雄--天生自然java开发常用类库学习笔记:对象克隆技术

    class Person implements Cloneable{ // 实现Cloneable接口表示可以被克隆 private String name ; public Person(Strin ...

  3. java 复制对象 (克隆接口 与 序列化)

    关于java对象复制我们在编码过程经常会碰到将一个对象传递给另一个对象,java中对于基本型变量采用的是值传递,而对于对象比如bean传递时采用的是应用传递也就是地址传递,而很多时候对于对象传递我们也 ...

  4. js对象克隆

    大家都知道,js的对象是引用类型,如果直接var obj2 = obj,obj2和obj是共享同一个对象实体的,这往往不是我们想要的结果. 官方并没有给出通用的对象克隆方法: 我们给出以下几种写法: ...

  5. javascript 对象克隆

    浅克隆 先看代码: /** * 浅克隆 克隆传入对象,只克隆一层 * @param {any} source */ function shallowClone(source) { var tiaget ...

  6. js 对象克隆方法总结(不改变原对象)

    1.通用对象克隆: function clone(obj){ let temp = null; if(obj instanceof Array){ temp = obj.concat(); }else ...

  7. Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨

    Java对象克隆(Clone)及Cloneable接口.Serializable接口的深入探讨 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的克隆,就不得不说为什么 ...

  8. (转)Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨

    原文地址:http://blog.csdn.net/kenthong/article/details/5758884 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的 ...

  9. Object.clone()方法与对象的深浅拷贝

    转载:[https://www.cnblogs.com/nickhan/p/8569329.html] 引言 在某些场景中,我们需要获取到一个对象的拷贝用于某些处理.这时候就可以用到Java中的Obj ...

随机推荐

  1. 如何利用jsp实现防盗链功能

    index.jsp ----------------------------- Place your content here here is index jsp get header info a. ...

  2. vb 三种启动模式

    正常启动不用说了 就是虚拟机和显示部分在同一个程序里进行 直接关闭程序 就都关闭了 相当于我们普通的电脑, 有主机和显示器无界面启动 也很好理解 ,就是在后台启动虚拟机,如同服务器, 我们只有一个主机 ...

  3. 关于Unity中Vector2和Vector3的使用

    Vector2是用来定义和描述2D游戏内部的一些参数,像刚体的速度等等 Vector3是 1.鼠标点击屏幕后要转化为3D坐标的时候用到的定义和描述 2.两个物体之间的相对距离,或者说偏移量的变量类型

  4. MAC配置Xcode的Cocos2d-x环境

    Version:0.9 StartHTML:-1 EndHTML:-1 StartFragment:00000099 EndFragment:00003988 1.Mac配置环境变量,即编辑命令: o ...

  5. SSH框架环境搭建问题:Line: 230 - com/opensymphony/xwork2/spring/SpringObjectFactory.java:230:-1

    只是通过myeclipse搭建一个框架而已 启动tomcat时报错信息: File: SpringObjectFactory.java Method: getClassInstance Line: 2 ...

  6. 第三百七十八节,Django+Xadmin打造上线标准的在线教育平台—django自带的admin后台管理介绍

    第三百七十八节,Django+Xadmin打造上线标准的在线教育平台—django自带的admin后台管理介绍 配置django的admin数据库管理后台 首先urls.py配置数据库后台路由映射,一 ...

  7. 第三百二十三节,web爬虫,scrapy模块以及相关依赖模块安装

    第三百二十三节,web爬虫,scrapy模块以及相关依赖模块安装 当前环境python3.5 ,windows10系统 Linux系统安装 在线安装,会自动安装scrapy模块以及相关依赖模块 pip ...

  8. Android开发之获取相册照片和获取拍照照片二

    转至 http://blog.csdn.net/beyond0525/article/details/8940840 上一篇文章中讲解了照相机获取照片的时候遇到了可能取得的uri为null的状态,并给 ...

  9. (诊断)处理错误fatal error: Python.h: No such file or directory

    安装与Python版本对应的 python-dev 即可,比如: $ -dev

  10. 使用appledoc 生成技术API文档具体解释

    一. 首先安装 appledoc 第一步:使用终端命令进行下载安装 git clone git://github.com/tomaz/appledoc.git cd ./appledoc sudo s ...