02.理解浅拷贝
03.理解深拷贝
04.序列化进行拷贝
07.数组的拷贝
08.集合的拷贝
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
下面来看一看实现浅拷贝的一个例子
public class Subject { private String name; public Subject(String s) { name = s; } public String getName() { return name; } public void setName(String s) { name = s; } }
public class Student implements Cloneable { // 对象引用 private Subject subj; private String name; public Student(String s, String sub) { name = s; subj = new Subject(sub); } public Subject getSubj() { return subj; } public String getName() { return name; } public void setName(String s) { name = s; } /** * 重写clone()方法
*/ public Object clone() { //浅拷贝 try { // 直接调用父类的clone()方法 return super.clone(); } catch (CloneNotSupportedException e) { return null; } } } ``` ``` private void test1(){ // 原始对象 Student stud = new Student("杨充", "潇湘剑雨"); System.out.println("原始对象: " + stud.getName() + " - " + stud.getSubj().getName()); // 拷贝对象 Student clonedStud = (Student) stud.clone(); System.out.println("拷贝对象: " + clonedStud.getName() + " - " + clonedStud.getSubj().getName()); // 原始对象和拷贝对象是否一样: System.out.println("原始对象和拷贝对象是否一样: " + (stud == clonedStud)); // 原始对象和拷贝对象的name属性是否一样 System.out.println("原始对象和拷贝对象的name属性是否一样: " + (stud.getName() == clonedStud.getName())); // 原始对象和拷贝对象的subj属性是否一样 System.out.println("原始对象和拷贝对象的subj属性是否一样: " + (stud.getSubj() == clonedStud.getSubj())); stud.setName("小杨逗比"); stud.getSubj().setName("潇湘剑雨大侠"); System.out.println("更新后的原始对象: " + stud.getName() + " - " + stud.getSubj().getName()); System.out.println("更新原始对象后的克隆对象: " + clonedStud.getName() + " - " + clonedStud.getSubj().getName()); } ```
输出结果如下:
2019-03-23 13:50:57.518 24704-24704/com.ycbjie.other I/System.out: 原始对象: 杨充 - 潇湘剑雨 2019-03-23 13:50:57.519 24704-24704/com.ycbjie.other I/System.out: 拷贝对象: 杨充 - 潇湘剑雨 2019-03-23 13:50:57.519 24704-24704/com.ycbjie.other I/System.out: 原始对象和拷贝对象是否一样: false 2019-03-23 13:50:57.519 24704-24704/com.ycbjie.other I/System.out: 原始对象和拷贝对象的name属性是否一样: true 2019-03-23 13:50:57.519 24704-24704/com.ycbjie.other I/System.out: 原始对象和拷贝对象的subj属性是否一样: true 2019-03-23 13:50:57.519 24704-24704/com.ycbjie.other I/System.out: 更新后的原始对象: 小杨逗比 - 潇湘剑雨大侠 2019-03-23 13:50:57.519 24704-24704/com.ycbjie.other I/System.out: 更新原始对象后的克隆对象: 杨充 - 潇湘剑雨大侠
可以得出的结论
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。
下面是实现深拷贝的一个例子。只是在浅拷贝的例子上做了一点小改动,Subject 和CopyTest 类都没有变化。
public class Student implements Cloneable { // 对象引用 private Subject subj; private String name; public Student(String s, String sub) { name = s; subj = new Subject(sub); } public Subject getSubj() { return subj; } public String getName() { return name; } public void setName(String s) { name = s; } /** * 重写clone()方法 *
*/ public Object clone() { // 深拷贝,创建拷贝类的一个新对象,这样就和原始对象相互独立 Student s = new Student(name, subj.getName()); return s; } } ```
输出结果如下:
2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 原始对象: 杨充 - 潇湘剑雨 2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 拷贝对象: 杨充 - 潇湘剑雨 2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 原始对象和拷贝对象是否一样: false 2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 原始对象和拷贝对象的name属性是否一样: true 2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 原始对象和拷贝对象的subj属性是否一样: false 2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 更新后的原始对象: 小杨逗比 - 潇湘剑雨大侠 2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 更新原始对象后的克隆对象: 杨充 - 潇湘剑雨
得出的结论
看一下下面案例,很简单,只需要实现Serializable这个接口。Android中还可以实现Parcelable接口。
public class ColoredCircle implements Serializable { private int x; private int y; public ColoredCircle(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } @Override public String toString() { return "x=" + x + ", y=" + y; } }
private void test3() { ObjectOutputStream oos = null; ObjectInputStream ois = null; try { // 创建原始的可序列化对象 DouBi c1 = new DouBi(100, 100); System.out.println("原始的对象 = " + c1); DouBi c2 = null; // 通过序列化实现深拷贝 ByteArrayOutputStream bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bos); // 序列化以及传递这个对象 oos.writeObject(c1); oos.flush(); ByteArrayInputStream bin = new ByteArrayInputStream(bos.toByteArray()); ois = new ObjectInputStream(bin); // 返回新的对象 c2 = (DouBi) ois.readObject(); // 校验内容是否相同 System.out.println("复制后的对象 = " + c2); // 改变原始对象的内容 c1.setX(200); c1.setY(200); // 查看每一个现在的内容 System.out.println("查看原始的对象 = " + c1); System.out.println("查看复制的对象 = " + c2); } catch (IOException e) { System.out.println("Exception in main = " + e); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { if (oos != null) { try { oos.close(); } catch (IOException e) { e.printStackTrace(); } } if (ois != null) { try { ois.close(); } catch (IOException e) { e.printStackTrace(); } } } }
输出结果如下:
2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 原始的对象 = x=100, y=100 2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 复制后的对象 = x=100, y=100 2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 查看原始的对象 = x=200, y=200 2019-03-23 13:53:48.096 25123-25123/com.ycbjie.other I/System.out: 查看复制的对象 = x=100, y=100
注意:需要做以下几件事儿:
得出的结论
如下所示
public void test4() { int[] lNumbers1 = new int[5]; int[] rNumbers1 = Arrays.copyOf(lNumbers1, lNumbers1.length); rNumbers1[0] = 1; boolean first = lNumbers1[0] == rNumbers1[0]; Log.d("小杨逗比", "lNumbers2[0]=" + lNumbers1[0] + ",rNumbers2[0]=" + rNumbers1[0]+"---"+first); int[] lNumbers3 = new int[5]; int[] rNumbers3 = lNumbers3.clone(); rNumbers3[0] = 1; boolean second = lNumbers3[0] == rNumbers3[0]; Log.d("小杨逗比", "lNumbers3[0]=" + lNumbers3[0] + ",rNumbers3[0]=" + rNumbers3[0]+"---"+second); }
打印结果如下所示
2019-03-25 14:28:09.907 30316-30316/org.yczbj.ycrefreshview D/小杨逗比: lNumbers2[0]=0,rNumbers2[0]=1---false 2019-03-25 14:28:09.907 30316-30316/org.yczbj.ycrefreshview D/小杨逗比: lNumbers3[0]=0,rNumbers3[0]=1---false
如下所示
public static void test5() { People[] lNumbers1 = new People[5]; lNumbers1[0] = new People(); People[] rNumbers1 = lNumbers1; boolean first = lNumbers1[0].equals(rNumbers1[0]); Log.d("小杨逗比", "lNumbers1[0]=" + lNumbers1[0] + ",rNumbers1[0]=" + rNumbers1[0]+"--"+first); People[] lNumbers2 = new People[5]; lNumbers2[0] = new People(); People[] rNumbers2 = Arrays.copyOf(lNumbers2, lNumbers2.length); boolean second = lNumbers2[0].equals(rNumbers2[0]); Log.d("小杨逗比", "lNumbers2[0]=" + lNumbers2[0] + ",rNumbers2[0]=" + rNumbers2[0]+"--"+second); People[] lNumbers3 = new People[5]; lNumbers3[0] = new People(); People[] rNumbers3 = lNumbers3.clone(); boolean third = lNumbers3[0].equals(rNumbers3[0]); Log.d("小杨逗比", "lNumbers3[0]=" + lNumbers3[0] + ",rNumbers3[0]=" + rNumbers3[0]+"--"+third); } public static class People implements Cloneable { int age; Holder holder; @Override protected Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } public static class Holder { int holderValue; } }
打印日志如下
2019-03-25 14:53:17.054 31093-31093/org.yczbj.ycrefreshview D/小杨逗比: lNumbers1[0]=org.yczbj.ycrefreshview.MainActivity$People@46a2c18,rNumbers1[0]=org.yczbj.ycrefreshview.MainActivity$People@46a2c18--true 2019-03-25 14:53:17.054 31093-31093/org.yczbj.ycrefreshview D/小杨逗比: lNumbers2[0]=org.yczbj.ycrefreshview.MainActivity$People@d344671,rNumbers2[0]=org.yczbj.ycrefreshview.MainActivity$People@d344671--true 2019-03-25 14:53:17.054 31093-31093/org.yczbj.ycrefreshview D/小杨逗比: lNumbers3[0]=org.yczbj.ycrefreshview.MainActivity$People@91e9c56,rNumbers3[0]=org.yczbj.ycrefreshview.MainActivity$People@91e9c56--true
构造函数和 clone() 默认都是浅拷贝
public static void test6() { ArrayList<People> lPeoples = new ArrayList<>(); People people1 = new People(); lPeoples.add(people1); Log.d("小杨逗比", "lPeoples[0]=" + lPeoples.get(0)); ArrayList<People> rPeoples = (ArrayList<People>) lPeoples.clone(); Log.d("小杨逗比", "rPeoples[0]=" + rPeoples.get(0)); boolean b = lPeoples.get(0).equals(rPeoples.get(0)); Log.d("小杨逗比", "比较两个对象" + b); } public static class People implements Cloneable { int age; Holder holder; @Override protected Object clone() { try { People people = (People) super.clone(); people.holder = (People.Holder) this.holder.clone(); return people; } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } public static class Holder implements Cloneable { int holderValue; @Override protected Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } } }
打印日志
2019-03-25 14:56:56.931 31454-31454/org.yczbj.ycrefreshview D/小杨逗比: lPeoples[0]=org.yczbj.ycrefreshview.MainActivity$People@46a2c18 2019-03-25 14:56:56.931 31454-31454/org.yczbj.ycrefreshview D/小杨逗比: rPeoples[0]=org.yczbj.ycrefreshview.MainActivity$People@46a2c18 2019-03-25 14:56:56.931 31454-31454/org.yczbj.ycrefreshview D/小杨逗比: 比较两个对象true
在某些特殊情况下,如果需要实现集合的深拷贝,那就要创建一个新的集合,然后通过深拷贝原先集合中的每个元素,将这些元素加入到新的集合当中。
public static void test7() { ArrayList<People> lPeoples = new ArrayList<>(); People people1 = new People(); people1.holder = new People.Holder(); lPeoples.add(people1); Log.d("小杨逗比", "lPeoples[0]=" + lPeoples.get(0)); ArrayList<People> rPeoples = new ArrayList<>(); for (People people : lPeoples) { rPeoples.add((People) people.clone()); } Log.d("小杨逗比", "rPeoples[0]=" + rPeoples.get(0)); boolean b = lPeoples.get(0).equals(rPeoples.get(0)); Log.d("小杨逗比", "比较两个对象" + b); } public static class People implements Cloneable { int age; Holder holder; @Override protected Object clone() { try { People people = (People) super.clone(); people.holder = (People.Holder) this.holder.clone(); return people; } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } public static class Holder implements Cloneable { int holderValue; @Override protected Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } } }
打印日志
2019-03-25 15:00:54.610 31670-31670/org.yczbj.ycrefreshview D/小杨逗比: lPeoples[0]=org.yczbj.ycrefreshview.MainActivity$People@46a2c18 2019-03-25 15:00:54.610 31670-31670/org.yczbj.ycrefreshview D/小杨逗比: rPeoples[0]=org.yczbj.ycrefreshview.MainActivity$People@d344671 2019-03-25 15:00:54.610 31670-31670/org.yczbj.ycrefreshview D/小杨逗比: 比较两个对象false