为什么要存在克隆?
首先new出来的对象时初始对象,如果对象里的数据是时刻发生变化的,除非你给初始的对象一一赋值或者使用构造器,
上面的也太繁琐了,而用引用就更不行了,旧对象发生变化那新对象也会跟着发生变化,所以产生了克隆
看源码
protected native Object clone() throws CloneNotSupportedException;
是native修饰的,说明克隆比自己一个个赋值要快
克隆分为两种
- 浅克隆:
- 深克隆
这两种区别就在深和浅,代表着深层次和浅层次,如果对象中只有那几种数据类型比如:int,String,char等,这两种就没有区别,
但是 如果对象里有另一个对象的引用,那这个对象有分为两层了,浅克隆只可怜那个最上面的一层,而下一层的引用都是一样的,深克隆是所有的层数都克隆
用图形来形象的表示这两种克隆
浅克隆
需要克隆的类实现Cloneable的接口,其他的都不用修改,
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
测试
public class TestPojo implements Cloneable{
public String a;
public TestPojo t;
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
public static void main(String[] args) throws Exception{
TestPojo t1 = new TestPojo();
t1.a = "555";
t1.t = new TestPojo(); //新的内部对象
TestPojo t2 = (TestPojo) t1.clone();
System.out.println(t2 == t1); //对象的==比较的是引用地址是否相同,equals比较的是值,instanceof比较的是左边是否是右边的子类
System.out.println(t2.t == t1.t);
}
}
深克隆
(1)将所有的引用类型实现Cloneable重写clone()方法
@Override
protected Object clone() throws CloneNotSupportedException {
TestPojo tp = (TestPojo) super.clone();
tp.t.clone();
return tp;
}
我这因为引用的它自己不用再重写一遍clone() 方法,和浅克隆的区别是修改了 clone() 的内容
测试
public class TestPojo implements Cloneable{
public String a;
public Test t;
@Override
protected Object clone() throws CloneNotSupportedException {
TestPojo tp = (TestPojo) super.clone();
tp.t = (Test) t.clone();
return tp;
}
}
另一个Test类
public class Test implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
public static void main(String[] args) throws Exception{
TestPojo t1 = new TestPojo();
t1.a = "555";
t1.t = new Test();
TestPojo t2 = (TestPojo) t1.clone();
System.out.println(t2 == t1);
System.out.println(t2.t == t1.t);
}
}
警告:
用这种方式实现深克隆一定要慎重,看上面的Test类,我是new了一个Test给TestPojo,如果在这样克隆的时候如果没有引用,也就是没有给TestPojo 内部对象一个实例,就深克隆了,那就会报错
java.lang.NullPointerException
这是一个很容易犯的错误
所以有的人就把clone() 方法加了try-catch
@Override
protected Object clone() throws CloneNotSupportedException {
TestPojo tp = (TestPojo) super.clone();
try {
tp.t = (Test) t.clone();
} catch (Exception e) {
e.printStackTrace(); //加就提醒错误,不加就不提醒运行下来
}
return super.clone();
}
上面这种方法就是治标不治本,解决不了根本性问题
(2)用序列化来实现浅克隆向深克隆转化(IO流解决)
public static void main(String[] args) throws Exception{
TestPojo t1 = new TestPojo();
t1.a = "555";
t1.t = new Test();
//将对象写到流里
ByteArrayOutputStream byteOut=new ByteArrayOutputStream();
ObjectOutputStream objOut=new ObjectOutputStream(byteOut);
objOut.writeObject(t1);
ByteArrayInputStream byteIn=new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream objInput=new ObjectInputStream(byteIn);
TestPojo t2 = (TestPojo) objInput.readObject();
System.out.println(t2 == t1);
System.out.println(t2.t == t1.t);
}
Test和TestPojo 实现 Serializable 接口就可以了,也可以不用实现Cloneable接口和重写从clone()方法了