您的位置:首页 > 编程语言 > Java开发

java的深浅拷贝与绕过构造函数获取对象的神奇之旅

2017-09-28 10:05 567 查看

一、产生一个对象一定要执行构造函数吗?

当然不是!!!!

     1、通过new产生一个对象

(1)先看new操作符后的类型,知道类型,分配相应大小的内存空间
(2)再调用构造函数,填充对象的各个域(对象初始化)
(3)构造函数执行后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部可以使用这个引用操作操纵这个对象

     2、反射-------请移步查看类加载机制以及Java-Reflect(反射)

(其本质还是newInstance()去找正确的构造)

     3、clone()----重点来啦

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

来段代码感受一下

public class Thing implements Cloneable {
public Thing() {
// TODO Auto-generated constructor stub
System.out.println("构造函数被执行......");
}

@Override
public Thing clone() {
Thing thing = null;
try {
thing = (Thing) super.clone();
} catch (Exception e) {
// TODO: handle exception
}
return thing;
}
}
(我们在构造函数输出一句话,验证clone对象时构造函数被执行了几次)
public class Client {
/**
* 对象拷贝时构造函数不被执行,Object类的clone方法的原理:</p>
* 从内存中(对内存)一二进制流的方式进行拷贝,重新分配一个内存块</p>
* 在运行时刻,Object中的clone()识别出你要复制的是哪个对象,然后为此对象分配空间,并进行对象的复制,</p>
* 将原始对象的内容一一复制到新对象的存储空间。</p>
* !!native方法效率远高于java中的非native方法
* @param args
*/
public static void main(String[] args) {
//产生一个对象
Thing thing = new Thing();
//拷贝一个对象
Thing clonething = thing.clone();

System.out.println(thing); //com.ashes.cloneTest.Thing@c17164
System.out.println(clonething); //com.ashes.cloneTest.Thing@1fb8ee3----新内存块
}
}

结果会是什么呢,我们的构造函数会被执行几次呢?

构造函数被执行......
com.ashes.cloneTest.Thing@de6ced
com.ashes.cloneTest.Thing@c17164

二、验证结果提问之什么是浅拷贝

看到此处,你可有疑问,为什么要实现Cloneable接口?clone()为什么是@Override?这个异常必须捕获吗?

1、浅拷贝

Object类提供的方法clone只是拷贝对象,其对象内部的数组,引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝。

      (1)被复制的类需要实现Cloneable接口(不实现的话在调用clone()会抛出CloneNotSupportedException)
该接口为标记接口(不含有任何方法)
/*** Eclipse Class Decompiler plugin, copyright (c) 2012 Chao Chen (cnfree2000@hotmail.com) ***/
package java.lang;

public abstract interface Cloneable {
}
     
     (2)覆盖clone(),访问修饰符设为public,方法中调用super.clone()得到需要的复制对象,native方法效率远高于非native方法哦。这也是为什么我们复制对象不新写一个类的关键原因。

     (3)
CloneNotSupportedException
 -
如果对象的类不支持 
Cloneable
 接口,则重写 
clone
 方法的子类也会抛出此异常,以指示无法复制某个实例。所以必须捕获异常。

2、深拷贝

clone()到底有什么功能,又有什么不足呢?
public class Thing implements Cloneable {

//定义一个私有变量
private ArrayList<String> arrayList = new ArrayList<String>();

public Thing() {
// TODO Auto-generated constructor stub
System.out.println("构造函数被执行......");
}

@Override
public Thing clone() {
Thing thing = null;
try {
thing = (Thing) super.clone();
} catch (Exception e) {
// TODO: handle exception
}
return thing;
}

//设置HashMap的值
public void setValue(String value) {
this.arrayList.add(value);
}

//取得arrayList的值
public ArrayList<String> getValue() {
return this.arrayList;
}
}

public class Client {
public static void main(String[] args) {
//定义一个对象
Thing thing = new Thing();
//设置一个值
thing.setValue("Ashes");
//拷贝一个对象
Thing cloneThing = thing.clone();
cloneThing.setValue("MushRoom");

System.out.println("原对象  ====> " + thing.getValue());
System.out.println("复制的新对象  ====>" + cloneThing.getValue());
}
}

结果会和我们湘的一样吗???
构造函数被执行......
原对象  ====> [Ashes, MushRoom]
复制的新对象  ====>[Ashes, MushRoom]

(1)为什么我明明修改的是复制的新对象,但是原对象自己也改变了???

浅拷贝:是指在拷贝欧诺对象的时候,对于基本数据类型的变量会重新复制一份,而对于引用类型的变量,只是对引用进行拷贝,没有对指向的对象进行拷贝。
所以,在这里原始对象及其副本引用的是同一个对象。

深拷贝:是指在拷贝对象时,同时会对引用指向的对象进行拷贝。
因此,深浅拷贝的区别在于: 是否对对象中的引用变量所指向的对象进行拷贝。

再来回顾刚刚的代码
public class Thing implements Cloneable {

//定义一个私有变量
private ArrayList<String> arrayList = new ArrayList<String>();

public Thing() {
// TODO Auto-generated constructor stub
System.out.println("构造函数被执行......");
}

@Override
public Thing clone() {
Thing thing = null;
try {
thing = (Thing) super.clone();
thing.arrayList = (ArrayList<String>) this.arrayList.clone();
} catch (Exception e) {
// TODO: handle exception
}
return thing;
}

//设置HashMap的值
public void setValue(String value) {
this.arrayList.add(value);
}

//取得arrayList的值
public ArrayList<String> getValue() {
return this.arrayList;
}
}


我只是简单的添加一行代码,结果又会有什么变化嘞?????
构造函数被执行......
原对象  ====> [Ashes]
复制的新对象  ====>[Ashes, MushRoom]


哇偶,我们的原始对象和副本是不是已经互不影响了,这是因为深拷贝的对对象中的引用变量所指向的对象进行拷贝了,原始对象和副本引用的不是同一个引用了,所以大家的修改自然不会相互影响。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐