Clone的理解
首先看张表了解一下分类以及区别:
类型 | 共同点 | 区别 | 什么情况下是所谓的类型 |
深度克隆 |
一个新的对象实例的所有 变量都含有与原来的对象 相同的值,对于基本类型 复制一份新产生的对象 |
非基本类型指向被复制的 新对象 |
若某个对象的属性都为基础类型,则 它的clone为深度克隆 |
浅度克隆 |
非基本类型指向原对象,只 是一个引用 |
集合的默认clone或Add以及AddAll 集合的构造方法 System.arraycopy() |
要注意String的克隆是一个特例,首先要知道String克隆是一个浅度克隆,但是又因为String的特殊性,在克隆时会有两个String类型的引用,所以如果改变克隆得到的对象的值是不会改变被克隆的对象的值的(这里我们可以假定为深度克隆)
但是StringBuffer以及StringBuilder就不能够这么认为了,如果想要实现这两个类型的深度克隆,我们必须在类的clone方法中进行主动拷贝操作
一段代码来加强记忆:
public class TestClone { public static void main(String[] args){ ArrayList<InfoBean> lists=new ArrayList<>(); lists.add(new InfoBean("zyf", 23)); lists.add(new InfoBean("pyh", 18)); lists.add(new InfoBean("zxh", 23)); for(InfoBean ib:lists){ System.out.println(ib); } // 浅度克隆 ArrayList<InfoBean> lists2=(ArrayList<InfoBean>)lists.clone(); // 深度克隆 ArrayList<InfoBean> lists3=new ArrayList<>(); for(int i=0;i<lists.size();i++){ try { lists3.add((InfoBean)lists.get(i).clone()); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // 对list2浅度克隆的验证 lists2.get(1).name="hhhhh"; System.out.println("对list2浅度克隆的验证-----------------------------"); for(InfoBean ib:lists){ System.out.println(ib); } // 对list3深度克隆的验证 lists3.get(1).name="zzzzzz"; System.out.println("对list3浅度克隆的验证-----------------------------"); for(InfoBean ib:lists){ System.out.println(ib); } } } class InfoBean implements Cloneable{ public String name; public int age; public InfoBean(String name,int age){ this.name=name; this.age=age; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "InfoBean [name=" + name + ", age=" + age + "]"; } }
看一下输出结果:
从输出结果可以说明一切了吧!
接下来说一下实现克隆的3种基本方法:
1 通过实现Cloneable接口并重写Object的clone方法实现浅度克隆 |
2 通过实现Cloneable接口并重写Object的clone方法实现深度克隆 |
3 通过对象的序列化和反序列化实现深度克隆 |
第一种:
class InfoBean implements Cloneable{ public String name; public int age; public InfoBean(String name,int age){ this.name=name; this.age=age; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "InfoBean [name=" + name + ", age=" + age + "]"; } }
第二种:
class InfoBean implements Cloneable{ public String name; public int age; public InfoBean(String name,int age){ this.name=name; this.age=age; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "InfoBean [name=" + name + ", age=" + age + "]"; } } class InfoBean2 implements Cloneable{ public String name; public int age; public InfoBean bean; public InfoBean2(String name,int age){ this.name=name; this.age=age; } @Override protected Object clone() throws CloneNotSupportedException { InfoBean2 ib2=(InfoBean2)super.clone(); ib2.bean=(InfoBean)bean.clone(); //这里的第二个bean是由上一句克隆过来的,是成员变量 return ib2; } @Override public String toString() { return "InfoBean2 [name=" + name + ", age=" + age + ", bean=" + bean + "]"; } }
第三种:
class CloneUtil{ public static<T extends Serializable>T clone(T obj){ T cloneObj =null; try{ ByteArrayOutputStream byteOut=new ByteArrayOutputStream(); ObjectOutputStream objOut =new ObjectOutputStream(byteOut); objOut.writeObject(obj); objOut.close(); ByteArrayInputStream byteIn =new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream objIn =new ObjectInputStream(byteIn); cloneObj =(T)objIn.readObject(); objIn.close(); }catch(IOException e){ e.printStackTrace(); }catch(ClassNotFoundException e){ e.printStackTrace(); } return cloneObj; } }