有些时候,我们需要对创建一个和已有对象A完全相同的新对象B,但是这个B不是A的引用,即A和B是两个完全独立的对象,虽然他们的属性相同,修改A的任何属性都不会对B产生影响,这个时候就要用到clone啦
clone有两种:
1深克隆:对克隆对象中所有的引用属性对象都进行克隆。
2浅克隆:仅克隆对象的基本类型数据和引用,即只克隆引用对象的地址,而不是克隆被引用的对象。(String类型除外,它表面上和基本类型一样实现了深克隆)
下面通过举例说明
1、深克隆
public class Test { public static void main(String[] args) { Stu stu1=new Stu(); stu1.setAge(5); stu1.setName("Zhang"); Stu stu2=(Stu)stu1.clone(); stu2.setName("Cheng"); System.out.println(stu1.getAge()); System.out.println(stu1.getName()); System.out.println(stu2.getAge()); System.out.println(stu2.getName()); } } public class Stu implements Cloneable{ String name; int age; 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 Object clone() { Stu stu=null; try{ stu=(Stu)super.clone(); }catch(CloneNotSupportedException ex) { ex.printStackTrace(); } return stu; } }
输出:
5
Zhang
5
Cheng
克隆有两点需要注意:1.必须实现Cloneable接口,假如不实现这个接口直接实现clone方法会抛出CloneNotSupport异常
2、必须实现clone方法,且方法必须是public的,这是因为Object本身就有个方法clone,不过这个方法时protected,另外这个方法时native方法, 效率比非native方法高。
2、浅拷贝
public class Stu implements Cloneable{ String name; int age; 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 String toString() { return "age="+age+" name="+name; } } public class Test { static class League implements Cloneable { int level; Stu stu; public int getLevel() { return level; } public void setLevel(int level) { this.level = level; } public Stu getStu() { return stu; } public void setStu(Stu stu) { this.stu = stu; } public String tosString() { return "level="+level+" age="+stu.getAge()+" name="+stu.getName(); } public Object clone() { League league=null; try{ league=(League)super.clone(); }catch(CloneNotSupportedException ex) { ex.printStackTrace(); } //league.stu=(Stu)stu.clone(); return league; } } public static void main(String[] args) { Stu stu1=new Stu(); stu1.setAge(5); stu1.setName("Zhang"); League league1=new League(); league1.setLevel(2); league1.setStu(stu1); League league2=(League)league1.clone(); league2.getStu().setName("Cheng"); System.out.println(league1.tosString()); System.out.println(league2.tosString()); } }
输出:
level=2 age=5 name=Cheng
level=2 age=5 name=Cheng
这里进行克隆过后,对克隆对象的修改会影响到被克隆对象,那么怎么才能避免呢
只要在League的对象属性Stu,也实现Clone即可,另外在League的clone方法里面加上league.stu=(Stu)stu.clone();即可
如下
public class Test { static class League implements Cloneable { int level; Stu stu; public int getLevel() { return level; } public void setLevel(int level) { this.level = level; } public Stu getStu() { return stu; } public void setStu(Stu stu) { this.stu = stu; } public String tosString() { return "level="+level+" age="+stu.getAge()+" name="+stu.getName(); } public Object clone() { League league=null; try{ league=(League)super.clone(); }catch(CloneNotSupportedException ex) { ex.printStackTrace(); } league.stu=(Stu)stu.clone(); return league; } } public static void main(String[] args) { Stu stu1=new Stu(); stu1.setAge(5); stu1.setName("Zhang"); League league1=new League(); league1.setLevel(2); league1.setStu(stu1); League league2=(League)league1.clone(); league2.getStu().setName("Cheng"); System.out.println(league1.tosString()); System.out.println(league2.tosString()); } } public class Stu implements Cloneable{ String name; int age; 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 String toString() { return "age="+age+" name="+name; } public Object clone() { Stu stu=null; try{ stu=(Stu)super.clone(); }catch(CloneNotSupportedException ex) { ex.printStackTrace(); } return stu; } }
输出
level=2 age=5 name=Zhang
level=2 age=5 name=Cheng
另外不是所有的类都可以实现深度克隆的,包含StringBuilder的类不能被深度克隆,因为该类没有重载clone方法,并且该类是一个final类,无法实现clone。