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