java基础知识总结--对象的克隆
前提:在Java语言中所有的类的都是缺省的继承Java语言中的Object类的,
protected native Object clone() throws CloneNotSupportedException;
它还是一个native的方法,大家都知道native的方法是非Java语言实现的代码,供Java语言调用,因为Java程序是运行在虚拟机上的,要想访问到比较低层的与操作系统相关的就没有办法了,只能由靠近操作系统的语言实现。
每一个对象直接或者间接的继承Object,因此他们都含有clone()方法,但是这个方法是Protected,所以不能在类外边访问。要想实现对一个对象的复制,就需要对clone()方法进行覆盖。
为什么要克隆?
克隆的对象可能包含一些已经修改过的属性,而new出来的对象都是初始化时候的值,所以当需要一个新的对象保存当前对象状态的时候就要靠clone()方法了。那么如果把这个对象的临时属性一个一个的赋值给新new出来的变量就会比较麻烦;而且clone()方法是非Java语言实现的更接近低层,所以速度比较快。
注意:我们常见的Object a=new Object();Object b;b=a;这种形式的代码复制的是引用,即对象在内存中的地址,a和b对象仍然指向了同一个对象。通过clone()方法复制的对象跟原来的对象是同时独立存在的。
如何实现克隆?
两种不同的克隆方法:浅克隆(shallowclone)和深克隆(deepclone) 。在Java语言中,数据类型分为基本数据类型和引用类型,其中引用数据类型主要包括类、接口、数组等复杂的数据类型。浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制。
一、浅克隆的一般步骤:
- 被复制的类需要实现Clonable接口。该接口为标记接口,里边不含任何的方法。
- 覆盖clone()方法,访问修饰符设为public,方法中调用super.clone()方法得到需要的复制对象。
这就是浅克隆,两个对象引用分别指向的是不同的堆内存空间。这里我们能看到,在学生这个类里面的所有成员变量都是基本数据类型,所以这个时候使用浅克隆是完全没有问题的,因为成员变量不涉及到引用数据类型。
二、深克隆的一般步骤:
深克隆和浅克隆的区别就是在一个类里边如果有引用类型的变量的话,依然使用浅克隆的方法进行对象引用的复制,那么出现的结果就是对象里的引用类型变量只是变量的复制,实际上并没有为复制的引用类型变量重新开辟空间。所以,为了达到真正的复制对象,针对引用类型变量不单单是变量的复制,我们需要将引用类型变量可复制化,并且还要修改clone()方法。
Eg:在学生类里边加入地址类:
深克隆的一般步骤:
- 当某一个类A是另一个类B的成员变量的时候,那么类A也要实现Clonable()这个接口,并且重写clone()方法。
- 类B也要实现Clonable()这个接口,并且在类B的实现代码里边也要重写clone()方法。
浅克隆和深克隆的比较?
1、浅克隆:在前克隆中,如果原型对象的成员变量是值的类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量(引用类型)指向相同的内存地址。
2、深克隆:在深克隆中无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。
简单地说就是在深克隆中,除了对象本身被复制外,对象所包含的成员变量也将复制。
注意:如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时我们可以用序列化的方式来实现对象的深克隆。