软构实验踩坑——Java拷贝相关

关于Java中的拷贝问题

在实验二中就因为Java中的拷贝机制踩了个坑,到实验2结束都不知道是哪里的问题,知道做到实验三才想起来到底是咋回事,故做此文。

import java.util.ArrayList;
import java.util.List;

public class foo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<Integer> l1 =  new ArrayList<Integer>();
		l1.add(3);
		List<Integer> l2 = l1;
		l2.set(0, 0);
		System.out.println(l1.get(0)+" "+l2.get(0));
	}
}

输出结果:0 0

直接复制,实际上是复制的引用,两者指向同一个对象,当l2中的成员变量进行变化时,l1的成员变量也跟着变化(这就是我Lab2中出现的bug之一)。可以考虑下面的方法

import java.util.ArrayList;
import java.util.List;

public class foo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<Integer> l1 =  new ArrayList<Integer>();
		l1.add(3);
		List<Integer> l2 = new ArrayList<Integer>();
		l2.addAll(l1);
		l2.set(0, 0);
		System.out.println(l1.get(0)+" "+l2.get(0));
	}
}

输出结果:3 0

浅拷贝:Object.clone():Creates and returns a copy of this object. The precise meaning of “copy” may depend on the class of the object. The general intent is that, for any object x, the expression:

 x.clone() != x

will be true, and that the expression:

 x.clone().getClass() == x.getClass()

will be true, but these are not absolute requirements. While it is typically the case that:

 x.clone().equals(x)

will be true, this is not an absolute requirement.

代码:

package P3;

import java.util.*;

public class Person implements Cloneable{

	private int age;
	private String name;
	private List<Person> friendsList = new LinkedList<>();
	boolean visit = false;
	
	public Person(String string,int age) {
		this.name = string;
		this.age = age;
	}

	void addFriend(Person p)
	{
		friendsList.add(p);
	}
	
	String getName()
	{
		return new String(name);
	}
	
	/**
	 * @return the friendsList
	 */
	public List<Person> getFriendsList() {
		return friendsList;
	}

	/**
	 * @param friendsList the friendsList to set
	 */
	public void setFriendsList(List<Person> friendsList) {
		this.friendsList = friendsList;
	}

	/**
	 * @return the age
	 */
	public int getAge() {
		return age;
	}

	/**
	 * @param age the age to set
	 */
	public void setAge(int age) {
		this.age = age;
	}

	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * @param visit the visit to set
	 */
	public void setVisit(boolean visit) {
		this.visit = visit;
	}

	int getAge(Person p)
	{
		int res = this.age;
		return res;
	}
	List<Person> getFriends()
	{
		return friendsList;
	}
	
	public Object Clone()
	{
		try {
			return (Person)super.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	}
}

package P3;

import java.util.LinkedList;
import java.util.List;

public class test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<Person> l1 = new LinkedList<Person>();
		List<Person> l2 = new LinkedList<Person>();
		Person p1 = new Person("A",12);
		Person p = new Person("C",9);
		Person l = new Person("D",8);
		l1.add(p);
		l2.add(l);
		p1.setFriendsList(l1);
		Person p2 = (Person) p1.Clone();
		System.out.println(p1.getName()+" "+p1.getAge());
		System.out.println(p1.getFriendsList().size());
		System.out.println(p2.getName()+" "+p2.getAge());
		System.out.println(p2.getFriendsList().size());
		p2.setAge(10);
		p2.setName("B");
		p2.addFriend(l);
		System.out.println(p1.getName()+" "+p1.getAge());
		System.out.println(p1.getFriendsList().size());
		System.out.println(p2.getName()+" "+p2.getAge());
		System.out.println(p2.getFriendsList().size());
	}
}

输出结果为:

A 12
1
A 12
1
A 12
2
B 10
2

p2作为由p1调用clone 得到的对象,当p2的name和age发生变化时都不会影响到p1相关属性的变化,但是当p2对其List操作时,p1的List也受到影响。由此可以得到clone主要操作为:创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。对于基本类型,直接拷贝其值,对于实例对象,拷贝其地址医用,因此才会出现新对象与原有对象公用一个实例变量,对于String直接拷贝其地址引用,但是在修改时,生成一个新的字符串。

解决方法:

可以考虑在clone函数上做手脚,进行修改。但是可能会影响程序的性能。

	public Object Clone()
	{
		Person p = null;
		try {
			p = (Person)super.clone();
			p.setFriendsList(new LinkedList<Person>(p.getFriendsList()));
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
		return p;
	}

测试结果

A 12
1
A 12
1
A 12
1
B 10
2

深拷贝:创造一个新的对象,并且新的对象与母对象之间不存在共享引用。序列化

package P3;

import java.io.*;
import java.io.Serializable;
import java.util.*;

public class Person implements Serializable{

	private static final long serialVersionUID = 2335521992258577660L;
	private int age;
	private String name;
	private List<Person> friendsList = new LinkedList<>();
	boolean visit = false;
	
	public Person(String string,int age) {
		this.name = string;
		this.age = age;
	}

	void addFriend(Person p)
	{
		friendsList.add(p);
	}
	
	String getName()
	{
		return new String(name);
	}
	
	/**
	 * @return the friendsList
	 */
	public List<Person> getFriendsList() {
		return friendsList;
	}

	/**
	 * @param friendsList the friendsList to set
	 */
	public void setFriendsList(List<Person> friendsList) {
		this.friendsList = friendsList;
	}

	/**
	 * @return the age
	 */
	public int getAge() {
		return age;
	}

	/**
	 * @param age the age to set
	 */
	public void setAge(int age) {
		this.age = age;
	}

	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * @param visit the visit to set
	 */
	public void setVisit(boolean visit) {
		this.visit = visit;
	}

	int getAge(Person p)
	{
		int res = this.age;
		return res;
	}
	List<Person> getFriends()
	{
		return friendsList;
	}

	public Object deepClone() throws Exception{
	    ByteArrayOutputStream bos = new ByteArrayOutputStream();
	    ObjectOutputStream oos = new ObjectOutputStream(bos);
	    oos.writeObject(this);
	    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
	    ObjectInputStream ois = new ObjectInputStream(bis);
	    return ois.readObject();
	}
}
package P3;

import java.util.LinkedList;
import java.util.List;

public class test {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		List<Person> l1 = new LinkedList<Person>();
		List<Person> l2 = new LinkedList<Person>();
		Person p1 = new Person("A",12);
		Person p = new Person("C",9);
		Person l = new Person("D",8);
		l1.add(p);
		l2.add(l);
		p1.setFriendsList(l1);
		Person p2 = (Person) p1.deepClone();
		System.out.println(p1.getName()+" "+p1.getAge());
		System.out.println(p1.getFriendsList().size());
		System.out.println(p2.getName()+" "+p2.getAge());
		System.out.println(p2.getFriendsList().size());
		p2.setAge(10);
		p2.setName("B");
		p2.addFriend(l);
		System.out.println(p1.getName()+" "+p1.getAge());
		System.out.println(p1.getFriendsList().size());
		System.out.println(p2.getName()+" "+p2.getAge());
		System.out.println(p2.getFriendsList().size());
	}
}

测试结果

A 12
1
A 12
1
A 12
1
B 10
2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值