Java实现克隆的方式?浅拷贝如何理解?

Java实现克隆的方式?浅拷贝如何理解?

1、浅复制(浅克隆)

浅拷贝(浅克隆):对一个对象进行clone生成新的对象,新的对象要开辟一块新的内存来存储,新对象中的基本类型属性和String类型属性都会开辟新的空间存储,但是如果是引用类型的属性,那这个引用类型的属性还是指向原对象的引用属性内存,当对新的对象或原对象的引用属性做出改变的时候,两方的引用属性类型的值同时做出改变。
1.先申明一个bean作为引用类型

public class Student {
private String name;
private String sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" +
name + ", sex=" + sex + ", age=" + age + "]";
}
public Student(){
}
public Student(String name, String sex, int
age) {
super();
this.name = name;
this.sex = sex;
this.age = age;
}
}

2.调用main方法进行验证

import java.io.Serializable;
import java.util.HashMap;
import java.util.Hashtable;
public class MapCloneTest { 
 public static void main(String[] args)
{
  Student zhangsan = new Student("zhangsan","男",25);
  HashMap map = new HashMap();
  map.put(1,zhangsan);  
  HashMap cloneMap =(HashMap) map.clone();
  System.out.println("*************************不做改变**********************************");
  System.out.println("未改变之前,  map的值:"+map.toString());
  System.out.println("未改变之前,cloneMap的值:"+cloneMap.toString());
  System.out.println("map和cloneMap是否指向同一内存地址:"+(map==cloneMap));
  System.out.println("map和cloneMap的hashcode:"+(map.hashCode()==cloneMap.hashCode()));
  System.out.println("map和cloneMap中存储的student是否指向同一内存地址:"+(map.get(1)==cloneMap.get(1)));
  System.out.println("map和cloneMap中存储的student值是否相同:"+(map.get(1).equals(cloneMap.get(1))));
  //对cloneMap中的值进行改变,看是否能影响到map
  Student cloneLisi =(Student) cloneMap.get(1);
  cloneLisi.setSex("女");
  System.out.println("*************************对map中的值做出修改***************************");
  System.out.println("改变之后,cloneMap的值:"+cloneMap.toString());
  System.out.println("改变之后, map的值:"+map.toString());
  System.out.println("*************************对map新增*********************************");
  Student lisi = new Student("lisi","男",18);
  map.put(2, lisi);
  System.out.println("改变之后,cloneMap的值:"+cloneMap.toString());
  System.out.println("改变之后, map的值:"+map.toString());
 }
}

输出结果:

*************************不做改变***********************************
未改变之前,     map的值:{1=Student [name=zhangsan, sex=男, age=25]}
未改变之前,cloneMap的值:{1=Student [name=zhangsan, sex=男, age=25]}
map和cloneMap是否指向同一内存地址:false
map和cloneMap的hashcode:true
map和cloneMap中存储的student是否指向同一内存地址:true
map和cloneMap中存储的student值是否相同:true
*************************对map中的值做出修改****************************
改变之后,cloneMap的值:{1=Student [name=zhangsan, sex=女, age=25]}
改变之后,     map的值:{1=Student [name=zhangsan, sex=女, age=25]}
*************************对map新增**********************************
改变之后,cloneMap的值:{1=Student [name=zhangsan, sex=女, age=25]}
改变之后,     map的值:{1=Student [name=zhangsan, sex=女, age=25], 2=Student [name=lisi, sex=男, age=18]}

从HashMap的克隆方法可以看出这样的几点
1.HashMap的clone方法生成新的对象,新的对象有自己独立的存储空间。
2.虽然HashMap的clone方法生成了新的对象,但新的HashMap和原来的HashMap所存储的引用类型都是指向的同一存储空间。
   浅复制(浅克隆)这种浅复制,其实也就是把被复制的这个对象的一些变量值拿过来了。

public class CloneTest1
{
 public static void main(String[] args) throws Exception
 {
  Student student = new Student();
  student.setAge(24);
  student.setName("niesong");
  Student student2 =(Student)student.clone();
  //这个是调用下面的那个方法,然后把这个这个对象Clone到student
  System.out.println("Age:"+ student2.getAge() + " " + "Name:" + student2.getName());
  System.out.println("---------------------");
  student2.setAge(23);
  //克隆后得到的是一个新的对象,所以重新写的是student2这个对象的值
   System.out.println(student.getAge());
  System.out.println(student2.getAge());
 } 
}
//克隆的对象必须实现Cloneable这个接口,而且需要重写clone方法
class Student implements Cloneable
{
 private int age;
 //定义为private说明这个成员变量只能被被当前类中访问,如果外部需要获得,那么就只能通过getAge方法进行获取
 private String name;
 public int getAge()
 {
  return age;
 }
 public void setAge(int age)
 {
  this.age = age;
 }
 public String getName()
 {
  return name;
 }
 public void setName(String name)
 {
  this.name = name;
 }
 @Override
 public Object clone() throws CloneNotSupportedException
 {
  Object object =super.clone();
  return object;
 }
}

2、深复制

情况1使用的是在克隆的时候手动进行深克隆

public class CloneTest2
{
 public static void main(String[] args) throws Exception
 {
  Teacher teacher = new Teacher();
  teacher.setAge(40);
  teacher.setName("teacher zhang");  
  Student2 student2 = new Student2();
  student2.setAge(14);
  student2.setName("lisi");
  student2.setTeacher(teacher);  
  Student2 student3 = (Student2)student2.clone();
  //这里是深复制,所以这时候Student2中的teacher就是teacher这个对象的一个复制,就和student3是student2的一个复制
  //所以下面teacher.setName只是对他原来的这个对象更改,但是复制的那个并没有更改
  System.out.println(student3.getAge());
  System.out.println(student3.getName());
  System.out.println(student3.getTeacher().getAge());
  teacher.setName("teacher niesong");//不会又任何影响
  System.out.println(student3.getTeacher().getName()); 
 } 
}
class Student2 implements Cloneable
{
 private int age;
 private String name;
 private Teacher teacher;
 public int getAge()
 {
  return age;
 }
 public void setAge(int age)
 {
  this.age = age;
 }
 public String getName()
 {
  return name;
 }
 public void setName(String name)
 {
  this.name = name;
 }
 public Teacher getTeacher()
 {
  return teacher;
 }
 public void setTeacher(Teacher teacher)
 {
  this.teacher = teacher;
 }
 @Override
 public Object clone() throws CloneNotSupportedException
 {
  //这一步返回的这个student2还只是一个浅克隆,
  Student2 student2 = (Student2)super.clone();
  //然后克隆的过程中获得这个克隆的student2,然后调用这个getTeacher这个方方法得到这个Teacher对象。然后实现克隆。在设置到这个student2中的Teacher。
  //这样实现了双层克隆使得那个teacher对象也得到了复制。
  student2.setTeacher((Teacher)student2.getTeacher().clone());
  //双层克隆使得那个teacher对象也得到了复制
  return student2;
 }
}
class Teacher implements Cloneable
{
 private int age;
 private String name;
 public int getAge()
 {
  return age;
 }
 public void setAge(int age)
 {
  this.age = age;
 }
 public String getName()
 {
  return name;
 }
 public void setName(String name)
 {
  this.name = name;
 }
 @Override
 public Object clone() throws CloneNotSupportedException
 {
  return super.clone();
 } 
}

3、利用serializable实现深复制

public class CloneTest3
{
 public static void main(String[] args) throws Exception
 {
  Teacher3 teacher3 = new Teacher3();
  teacher3.setAge(23);
  teacher3.setName("niesong");
  Student3 student3 = new Student3();
  student3.setAge(50);
  student3.setName("wutao");
  student3.setTeacher3(teacher3);
  
  Student3 ss = (Student3)student3.deepCopt();
  System.out.println(ss.getAge());
  System.out.println(ss.getName());
  
  System.out.println("---------------------");
  System.out.println(ss.getTeacher3().getAge());
  System.out.println(ss.getTeacher3().getName());
  
  System.out.println("-----------------------");  
  ss.getTeacher3().setAge(7777);
  ss.getTeacher3().setName("hhhhh");
  
  System.out.println(teacher3.getAge());
  System.out.println(teacher3.getName());
  //虽然上面的已经改了,但是改的是那个复制对象后的那个里面的,然后那个原来的那个里面的并没有改,下面验证:::
  
  System.out.println("-----------------");  
  System.out.println(ss.getTeacher3().getAge());
  System.out.println(ss.getTeacher3().getName());  
 }
 
}
class Teacher3 implements Serializable
{
//  上面的那个警告可以直接消除,除了使用在设置中不显示这个警告,还可以使用下面的这两条语句中的任何一条语句
// 这个serialVersionUID为了让该类别Serializable向后兼容
// private static final long serialVersionUID = 1L;
// private static final long serialVersionUID = 8940196742313994740L;
 private int age;
 private String name;
 public int getAge()
 {
  return age;
 }
 public void setAge(int age)
 {
  this.age = age;
 }
 public String getName()
 {
  return name;
 }
 public void setName(String name)
 {
  this.name = name;
 }
}
class Student3 implements Serializable
 {
  private static final long serialVersionUID = 1L;
  private int age;
  private String name;
  private Teacher3 teacher3;
  public int getAge()
  {
   return age;
  }
  public void setAge(int age)
  {
   this.age = age;
  }
  public String getName()
  {
   return name;
  }
  public void setName(String name)
  {
   this.name = name;
  }
  public Teacher3 getTeacher3()
  {
   return teacher3;
  }
  public void setTeacher3(Teacher3 teacher3)
  {
   this.teacher3 = teacher3;
  }
  //使得序列化student3的时候也会将teacher序列化
  public Object deepCopt() throws Exception
  {
   ByteArrayOutputStream bos = new ByteArrayOutputStream();
   ObjectOutputStream  oos = new ObjectOutputStream(bos);
   oos.writeObject(this);
   //将当前这个对象写到一个输出流当中,,因为这个对象的类实现了Serializable这个接口,所以在这个类中
   //有一个引用,这个引用如果实现了序列化,那么这个也会写到这个输出流当中
   
   ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
   ObjectInputStream ois = new ObjectInputStream(bis);
   return ois.readObject();
   //这个就是将流中的东西读出类,读到一个对象流当中,这样就可以返回这两个对象的东西,实现深克隆
  }
 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值