Java中,对八大基本数据类型:byte,char,short,int,long,float,double,boolean 的处理,是采用按值传递的(传递该值的一份克隆)。而对其它类型,则采用引用传递(指向该值的一个引用,是一个内存地址)。
对于 Test one = new Test(); Test two = one; 这种形式的赋值,对象one 和 two都是用同一个引用(可以认为one是一个人的名字,two是他的花名。两个名字都代表同一个人)。
这样的引用传递,带来的效果是,其中一个对象的改变,将对另一个对象带来相同的影响。
———————分————————-割—————————–线————————-
但是,实际开发中,经常会遇到一种需求:需要获取对象A的一份克隆:对象B,但是对象B是独立的。对B的操作不能影响A。对此需求,java.lang.Object.clone()方法,提供了很好的支持。
打开clone()源码: protected native Object clone() throws CloneNotSupportedException;、
我们可以了解到,clone()是一个protected修饰的空方法,表示异包的子类拥有访问权限。本来,其它类在不同的包中生成对象时,是无法直接调用clone方法的。不过,Object是所有类的默认基类,因此,我们所使用的类,都直接或间接地继承了该方法。
native关键字说明它是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。它的实现交给本地操作系统。因此,我们应该在子类中覆写clone()方法,并且显示调用父类Object中的clone()方法,来间接调用本地方法,对其进行具体的克隆实现。
克隆分为浅克隆和深克隆两种。A对象中包含的是一些基本数据类型时,使用浅克隆就可以了。而当A对象内部还包含有其它对象的时候,就需要使用深克隆来进行A对象的深度克隆了。
而克隆有一个前提条件,克隆对象所属的类,必须是一个实现了Cloneable接口的类。
接口的声明:public interface Cloneable {} //它是一个标识接口,无方法,仅用来表示它拥有某种能力
克隆技术的实现步骤分为两步:1、实现Cloneable标识接口;2、覆写clone()方法
深克隆代码如下:
public class Test implements Cloneable {
private Check check = new Check(); //this对象内部含有另一个对象: check
public Check getCheck() {
return check;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Test test = (Test) super.clone();
test.check = (Check) this.getCheck().clone(); //标识1
return test;
}
public static void main(String[] args) throws CloneNotSupportedException {
Test t1 = new Test();
Test t2 = (Test) t1.clone();
}
}
class Check implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
ps:如果Check类没有实现Cloneable接口,它是没有克隆能力的。此时标识1处在编译的时候,是没有语法错误的。只是在运行时,因为Check类没有克隆能力,虚拟机会报异常:CloneNotSupportedException
另外,还有一种克隆方法,是通过序列化的方式进行克隆。本篇暂不叙述。