Java對象的深層復制是指Java對象A本身被clone成新對象B,同時A的屬性也是被clone成新對象,賦值到A的各個屬性上去,A與B的相同屬性都引用到不同的對象;
Java對象的淺層復制是指Java對象A本身被clone成新對象B,但A的屬性沒有被clone處理,只是把A的各個屬性所指的對象賦值到B對應的屬性上,A與B的相同屬性都引用到同一個對象。
在java中,默認是淺層復制的,如果要復制的對象中只含有基本數據類型和String類型,
那么淺層復制和淺層復制是沒有區別的,所以你可以放心的使用默認的淺層復制,
如果屬性有Date或其他自定的數據類,則一定的小心了,因為這時淺層復制后對象B的屬性birthday與原始對象A的對應屬性birthday,都是引用到同一個對象TestVo ,
如果通過B.birthday的方法改了TestVo的值,則修改會影響到A.birthday,這時也就會發生互串的情況
以下三種方法可以實現淺層復制:
(1)通過調用對象set方法來實現,屬性個數比較少時適用
public class TestVo implements Cloneable{ private String name; private int age; private Date birthday; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } protected TestVo clone() { TestVo testVo = null; try { testVo = (TestVo) super.clone(); } catch (Exception e) { e.printStackTrace(); } return testVo; } }
public static void test1(){ TestVo t1 = new TestVo(); t1.setAge(10); t1.setName("劉備"); t1.setBirthday(DateUtil.strToDate("2016-10-10 12:12:12")); TestVo t2 = new TestVo(); t2.setAge(t1.getAge()); t2.setName(t1.getName()); t2.setBirthday(t1.getBirthday()); System.out.println("t1=="+t1.getAge()+","+t1.getName()+","+t1.getBirthday()); System.out.println("t2=="+t2.getAge()+","+t2.getName()+","+t2.getBirthday()); t2.setAge(20); t2.setName("張飛"); t2.setBirthday(DateUtil.strToDate("2016-11-11 13:13:13")); System.out.println("t3=="+t1.getAge()+","+t1.getName()+","+t1.getBirthday()); System.out.println("t4=="+t2.getAge()+","+t2.getName()+","+t2.getBirthday()); }
打印結果如下:
t1==10,劉備,Mon Oct 10 12:12:12 CST 2016
t2==10,劉備,Mon Oct 10 12:12:12 CST 2016
t3==10,劉備,Mon Oct 10 12:12:12 CST 2016
t4==20,張飛,Fri Nov 11 13:13:13 CST 2016
這時候淺層復制和深層復制打到的效果是一樣的,所以對t2的值修改,不會影響t1對象的值,
但是如果date類型的屬性值,按照以下方法設置值,則會影響到t1中的值
public static void test1(){ TestVo t1 = new TestVo(); t1.setAge(10); t1.setName("劉備"); t1.setBirthday(DateUtil.strToDate("2016-10-10 12:12:12")); TestVo t2 = new TestVo(); t2.setAge(t1.getAge()); t2.setName(t1.getName()); t2.setBirthday(t1.getBirthday()); System.out.println("t1=="+t1.getAge()+","+t1.getName()+","+t1.getBirthday()); System.out.println("t2=="+t2.getAge()+","+t2.getName()+","+t2.getBirthday()); t2.setAge(20); t2.setName("張飛"); //t2.setBirthday(DateUtil.strToDate("2016-11-11 13:13:13")); t2.getBirthday().setTime(1000); System.out.println("t3=="+t1.getAge()+","+t1.getName()+","+t1.getBirthday()); System.out.println("t4=="+t2.getAge()+","+t2.getName()+","+t2.getBirthday()); }
打印結果如下:
t1==10,劉備,Mon Oct 10 12:12:12 CST 2016
t2==10,劉備,Mon Oct 10 12:12:12 CST 2016
t3==10,劉備,Thu Jan 01 08:00:01 CST 1970
t4==20,張飛,Thu Jan 01 08:00:01 CST 1970
這時候t2值修改后,t1頁跟着修改了,Date是一個可變的類,這樣淺層復制就出現屬性值互串的情況,
通過監聽引用地址t1.getBirthday() == t2.getBirthday(),發現:
t2.setBirthday(DateUtil.strToDate("2016-11-11 13:13:13"));這樣設置值,t1和t2的引用地址不一樣,所有t2修改不會對t1產生影響
t2.getBirthday().setTime(1000);這樣設置值,t1.getBirthday() == t2.getBirthday()控制台返回true,說明t1和t2的引用同一個地址,所有會相互影響,
如有不對之處,請不吝賜教,歡迎指正
(2) 通過復寫object.clone來實現
TestVo t1 = new TestVo(); t1.setAge(10); t1.setName("劉備"); t1.setBirthday(DateUtil.strToDate("2016-10-10 12:12:12")); TestVo t2 = t1.clone();
(3)通過工具類,BeanUtils, 屬性個數很多時候適用
TestVo t1 = new TestVo(); t1.setAge(10); t1.setName("劉備"); t1.setBirthday(DateUtil.strToDate("2016-10-10 12:12:12")); TestVo t2 = new TestVo(); BeanUtils.copyProperties(t2, t1);
(2)(3)和(1)的打印結果是一樣的,同樣,如果(2)(3)的date類型也按照如下修改值,也會影響t1的值,和(1)的一樣
t2.getBirthday().setTime(1000);
再看下面的例子:
public class TestVoB { private int sex; public TestVoB(int sex){ this.sex = sex; } public void sumValue(){ this.sex += 10; } public String toString(){ return Integer.toString(sex); } public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } }
public class TestVo implements Cloneable{ private String name; private int age; private Date birthday; TestVoB testVoB = new TestVoB(222); public TestVoB getTestVoB() { return testVoB; } public void setTestVoB(TestVoB testVoB) { this.testVoB = testVoB; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } protected TestVo clone() { TestVo testVo = null; try { testVo = (TestVo) super.clone(); } catch (Exception e) { e.printStackTrace(); } return testVo; } }
public static void test2() throws CloneNotSupportedException{ TestVo t1 = new TestVo(); t1.setAge(10); t1.setName("劉備"); t1.setBirthday(DateUtil.strToDate("2016-10-10 12:12:12")); TestVo t2 = t1.clone(); System.out.println("t1=="+t1.getAge()+","+t1.getName()+","+t1.getBirthday()); System.out.println("t2=="+t2.getAge()+","+t2.getName()+","+t2.getBirthday()); t2.setAge(20); t2.setName("張飛"); t2.setBirthday(DateUtil.strToDate("2016-11-11 13:13:13")); t2.testVoB.sumValue(); System.out.println("t3=="+t1.getAge()+","+t1.getName()+","+t1.getBirthday()+","+t1.testVoB); System.out.println("t4=="+t2.getAge()+","+t2.getName()+","+t2.getBirthday()+","+t2.testVoB); }
打印結果如下:
t1==10,劉備,Mon Oct 10 12:12:12 CST 2016
t2==10,劉備,Mon Oct 10 12:12:12 CST 2016
t3==10,劉備,Mon Oct 10 12:12:12 CST 2016,232
t4==20,張飛,Fri Nov 11 13:13:13 CST 2016,232
可以看出t2中的testVoB值的修改影響了t1中的testVoB,說明兩個引用指向同一個對象。
一般情況下,用淺層復制就夠了,但是在特殊情況下,淺層復制不能滿足我們的業務需求,這時候就需要深層復制,實現深層復制只需要在上面的例子中修改一下就可以:
1.讓TestVoB 類也實現和TestVo類一樣的clone功能(實現Cloneable接口,重載clone()方法),
2.在TestVo的clone()方法中加入一句testVo.testVoB = testVoB.clone();
public class TestVoB implements Cloneable{ private int sex; public TestVoB clone() { TestVoB testVoB = null; try { testVoB = (TestVoB) super.clone(); } catch (Exception e) { e.printStackTrace(); } return testVoB; } public TestVoB(int sex){ this.sex = sex; } public void sumValue(){ this.sex += 10; } public String toString(){ return Integer.toString(sex); } public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } } public class TestVo implements Cloneable{ private String name; private int age; private Date birthday; TestVoB testVoB = new TestVoB(222); public TestVoB getTestVoB() { return testVoB; } public void setTestVoB(TestVoB testVoB) { this.testVoB = testVoB; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } protected TestVo clone() { TestVo testVo = null; try { testVo = (TestVo) super.clone(); } catch (Exception e) { e.printStackTrace(); } testVo.testVoB = testVoB.clone(); return testVo; } }
這時候再去執行,打印結果如下:
t1==10,劉備,Mon Oct 10 12:12:12 CST 2016
t2==10,劉備,Mon Oct 10 12:12:12 CST 2016
t3==10,劉備,Mon Oct 10 12:12:12 CST 2016,222
t4==20,張飛,Fri Nov 11 13:13:13 CST 2016,232
可以看到t2中的testVoB值的修改,t1中的testVoB沒有變化,說明兩個對象引用指向了不同的對象,實現了深層復制
以上只是本人自己的一些理解,如有不對的地方,請不吝賜教,共同學習
