zoukankan      html  css  js  c++  java
  • Java对象和集合的拷贝/克隆/复制

    昨天同事遇到了一个奇怪的问题,他需要将一个JavaBean拷贝一份,然后对新创建的Bean进行操作。但是他对新的Bean操作后,会影响旧的Bean的值。当听到这个问题的时候,我第一反应就是他的拷贝方法有问题,只是将aBean的内容复制给了bBean,但是在内存中指向的是同一个地址。这里就引出了两个关键词,浅拷贝深拷贝

    浅拷贝(浅克隆)

    被复制对象的所有变量值都和原来的对象的值相同,但是复制后的对象的引用仍然指向原来的对象。简单来说,就是对A进行拷贝生成B,只是将A的值复制给了B,内存中指向的是同一地址,影响就是改变B的同时,A的值也会改变。

    深拷贝(深克隆)

    被复制对象的所有变量值都和原来的对象的值相同,除了变量的值改变,也会创建新的指向变量的地址。源对象A和复制后的B,虽然内容是一样的,但是各自指向的地址不同,所以改变相互不受影响。

    那问题已经知道,Java的Bean对象要怎么进行深拷贝呢。

    一、Java对象克隆

    Java中对象的深克隆

    ①利用Object类的clone()方法。
    ②在派生类中重写基类的clone方法,并声明为public。
    ③在派生类的clone()方法中,调用super.clone()。
    ④在派生类中实现Cloneable接口。

    这是一个Student的类,重写了clone()方法。

    public class Student implements Cloneable {
    	private String name;
    	private int age;
    
    	public Student(String name, int age) {
    		super();
    		this.name = name;
    		this.age = 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() {
    		Object o = null;
    		try {
    			o = (Student)super.clone();
    		} catch (CloneNotSupportedException e) {
    			e.printStackTrace();
    		}
    		
    		return o;
    	}
    	@Override
    	public String toString() {
    		return "Student [name=" + name + ", age=" + age + "]";
    	}
    }
    

    测试clone

    public static void main(String[] args) { 
    	Student s1=new Student("张三",18);
    	System.out.println("修改前s1值:" + s1.toString());
    	
    	Student s2=(Student)s1.clone(); 
    	s2.setName("李四");
    	s2.setAge(20);
    	
    	//修改学生2后,不影响学生1的值。
    	System.out.println("修改后s1值:" + s1.toString());
    	System.out.println("s2的值:" + s2.toString());
    }
    

    控制台输出的结果如下:

    修改前s1值:Student [name=张三, age=18]
    修改后s1值:Student [name=张三, age=18]
    s2的值:Student [name=李四, age=20]
    

    上面的例子对象中的属性是基本类型,但是如果包含非基本类型,结果怎样呢,上代码,对Student类进行修改,加入Course类。
    Student类

    public class Student implements Cloneable {
    	
    	private String name;
    	private int age;
    	private Course course;
    	
    	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 Course getCourse() {
    		return course;
    	}
    	public void setCourse(Course course) {
    		this.course = course;
    	}
    	
    	public Student(String name, int age, Course course) {
    		super();
    		this.name = name;
    		this.age = age;
    		this.course = course;
    	}
    	
    	public Student() {
    	}
    	
    	public Object clone() {
    		Object o = null;
    		try {
    			o = (Student)super.clone();
    		} catch (CloneNotSupportedException e) {
    			e.printStackTrace();
    		}
    		
    		return o;
    	}
    	@Override
    	public String toString() {
    		return "Student [name=" + name + ", age=" + age + ", course=" + course + "]";
    	}
    	
    }
    

    Course类

    
    public class Course {
    	
    	private String name;
    	private int value;
    	
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public int getValue() {
    		return value;
    	}
    	public void setValue(int value) {
    		this.value = value;
    	}
    	
    	public Course(String name, int value) {
    		super();
    		this.name = name;
    		this.value = value;
    	}
    	public Course() {
    		
    	}
    	@Override
    	public String toString() {
    		return "Course [name=" + name + ", value=" + value + "]";
    	}
    	
    }
    

    测试克隆

    public static void main(String[] args) { 
    	
    	Student s1 = new Student();
    	s1.setName("张三");
    	s1.setAge(24);
    	
    	Course c = new Course();
    	c.setName("语文");
    	c.setValue(80);
    	
    	s1.setCourse(c);
    	System.out.println("修改前s1值:" + s1.toString());
    	
    	Student s2 = (Student)s1.clone();
    	s2.setName("李四");
    	s2.setAge(20);
    	
    	Course c2 = s2.getCourse();
    	c2.setName("数学");
    	c2.setValue(90);
    	
    	//修改学生2的Course后,影响学生1的Course。
    	System.out.println("修改后s1值:" + s1.toString());
    	System.out.println("s2的值:" + s2.toString());
    }
    

    控制台输出结果

    修改前s1值:Student [name=张三, age=24, course=Course [name=语文, value=80]]
    修改后s1值:Student [name=张三, age=24, course=Course [name=数学, value=90]]
    s2的值:Student [name=李四, age=20, course=Course [name=数学, value=90]]
    
    上面的例子说明调用clone方法,拷贝原始对象中的内容,对于基本数据类型,这样的操作是没有问题的,但是对于非基本类型,它们保存的仅仅是对象的引用。

    为了解决上面的问题,我们需要使用深度克隆方案。修改之后的Student类和Course类如下
    Student类

    public class Student implements Cloneable {
    	
    	private String name;
    	private int age;
    	private Course course;
    	
    	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 Course getCourse() {
    		return course;
    	}
    	public void setCourse(Course course) {
    		this.course = course;
    	}
    	
    	public Student(String name, int age, Course course) {
    		super();
    		this.name = name;
    		this.age = age;
    		this.course = course;
    	}
    	
    	public Student() {
    	}
    	
    	public Student clone() {
    		Student s = null;
    		try {
    			s = (Student)super.clone();
    			s.course = course.clone();
    		} catch (CloneNotSupportedException e) {
    			e.printStackTrace();
    		}
    		
    		return s;
    	}
    	@Override
    	public String toString() {
    		return "Student [name=" + name + ", age=" + age + ", course=" + course + "]";
    	}
    	
    }
    

    Course类

    
    public class Course implements Cloneable{
    	
    	private String name;
    	private int value;
    	
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public int getValue() {
    		return value;
    	}
    	public void setValue(int value) {
    		this.value = value;
    	}
    	
    	public Course(String name, int value) {
    		super();
    		this.name = name;
    		this.value = value;
    	}
    	public Course() {
    		
    	}
    	
    	public Course clone() {
    		Course c = null;
    		try {
    			c = (Course)super.clone();
    		} catch (CloneNotSupportedException e) {
    			e.printStackTrace();
    		}
    		
    		return c;
    	}
    	@Override
    	public String toString() {
    		return "Course [name=" + name + ", value=" + value + "]";
    	}
    	
    }
    

    测试方法使用之前的方法,下面的运行后的结果。

    修改前s1值:Student [name=张三, age=24, course=Course [name=语文, value=80]]
    修改后s1值:Student [name=张三, age=24, course=Course [name=语文, value=80]]
    s2的值:Student [name=李四, age=20, course=Course [name=数学, value=90]]
    

    根据结果可知,通过深度克隆后,clone后的对象非基本类的变量修改,不会对原对象造成影响。

    对于集合的Clone操作也一样,集中的属性如果是基本数据类型的话,循环赋值,或者使用addAll()方法都不会对原集合造成影响。若集合中存放了非基本数据类型的话,如上述中的Student对象,就必须对Student对象添加重写clone()方法。

  • 相关阅读:
    21.Merge Two Sorted Lists 、23. Merge k Sorted Lists
    34. Find First and Last Position of Element in Sorted Array
    leetcode 20. Valid Parentheses 、32. Longest Valid Parentheses 、301. Remove Invalid Parentheses
    31. Next Permutation
    17. Letter Combinations of a Phone Number
    android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )及屏幕适配注意事项
    oc 异常处理
    oc 类型判断
    oc Delegate
    oc 协议
  • 原文地址:https://www.cnblogs.com/ghq120/p/11603961.html
Copyright © 2011-2022 走看看