java深拷贝和浅拷贝

从今天开始将不定期更新一篇文章搞懂XXX系列,系列目录以后更新

第一篇:java深拷贝和浅拷贝,发现技术问题的请私信,评论,加qq指导!

1、浅拷贝:

将stu1的引用赋值给stu2,stu1和stu2指向内存堆中同一个对象,一个对象的改变会引起另一个对象的改变

2、深拷贝的几种实现方式

2.1、实现Cloneable接口,假设有依赖属性是类B,类B也需要实现Cloneable接口,假设类B有依赖属性C,C也要实现接口

比如 :

public class Student implements Cloneable {

	private static String staString = "static";
	
	private String myChineseName;
	
	private int age;
	
	private Addr addr;

	
	public String getMyChineseName() {
		return myChineseName;
	}

	public void setMyChineseName(String myChineseName) {
		this.myChineseName = myChineseName;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public Addr getAddr() {
		return addr;
	}

	public void setAddr(Addr addr) {
		this.addr = addr;
	}
	
	public Student() {}

	public Student(String myChineseName, int age, Addr addr) {
		super();
		this.myChineseName = myChineseName;
		this.age = age;
		this.addr = addr;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
	
}
public class Addr  implements Cloneable{

	private String city;
	
	private String proviceName;
	
	private DetailAddr detailAddr;

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getProviceName() {
		return proviceName;
	}

	public void setProviceName(String proviceName) {
		this.proviceName = proviceName;
	}

	
	public DetailAddr getDetailAddr() {
		return detailAddr;
	}

	public Addr(String city, String proviceName, DetailAddr detailAddr) {
		super();
		this.city = city;
		this.proviceName = proviceName;
		this.detailAddr = detailAddr;
	}

	public void setDetailAddr(DetailAddr detailAddr) {
		this.detailAddr = detailAddr;
	}

	public Addr() {}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}
	
}

C:

package my.java.deepclone;

public class DetailAddr implements Cloneable {

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public DetailAddr() {}

	public DetailAddr(String name) {
		super();
		this.name = name;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}

	
}

supper 的clone是一个本地方法,对于基础类型和包装类型的变量能够做到深拷贝,对于类是将对象的引用指向同一个地方,未拷贝对象,是浅拷贝。

 

2.2 java反射实现多次依赖的深拷贝

注意:利用反射的时候,类一定要有自己的默认构造方法,否则会报错。

package my.java.deepclone;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ObjectCopy {

	/**
	 *  是否是基本类型和包装类型
		* @Description: TODO(这里用一句话描述这个方法的作用) 
		* @param @param className
		* @param @return
		* @return boolean    返回类型 
		* @throws
	 */
	public static boolean isWrapClass(Class className) {
		if(className.isPrimitive()) {
			return true;
		}
	    if (className.equals(java.lang.Integer.class) ||
	        className.equals(java.lang.Byte.class) ||
	        className.equals(java.lang.Long.class) ||
	        className.equals(java.lang.Double.class) ||
	        className.equals(java.lang.Float.class) ||
	        className.equals(java.lang.Character.class) ||
	        className.equals(java.lang.Short.class) ||
	        className.equals(java.lang.String.class) ||
	        className.equals(java.lang.Boolean.class)) {
	        return true;
	    }
	    return false;
	}
	
	public static Object copy(Object source) {
		// 创建一个新的对象(空对象)
		Object target = null;

		try {
			// 获取源对象的class对象
			Class clz = source.getClass();
			// 源对象必须有空的构造器,否则会报错
			target = clz.newInstance();
			// 获取类中的所有属性
			Field[] fields = clz.getDeclaredFields();
			//变量类的所有属性
			for (Field field : fields) {
				/**
				 * 如果是静态的成员,则不需要深层克隆,因为静态成员属于类,对所有实例都共享,不能改变现有静态成员的引用指向
				 * 如果是final类型变量,则不能深层克隆,即使复制一份后也不能将它赋值给final类型变量
				 */
			    if (Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())) {  
                    continue;  
                }
			    // 获取属性名
				String fieldName = field.getName();
				
				// 根据属性名称获取setter/getter方法名,myChineseName 对应的方法只需要set+m大写+尾部即可
				String set = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
				String get = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
				
				// 根据方法名称获取方法对象,getMethod的参数是方法名称,方法形参
				Method method_set = clz.getMethod(set, field.getType());
				Method method_get = clz.getMethod(get);
				
				// 执行源对象的get方法,获取返回值
				Object returnVal = method_get.invoke(source);
			    
				//判断返回值的对象是否是基本类型和包装类型
				if(isWrapClass(field.getType())) {
					// 执行目标对象的set方法,将源对象方法的返回值作为参数设置给目标对象
					method_set.invoke(target, returnVal);
			    }else {
			    	System.out.println("非基本类型和包装类型"+ field.getType());
			    	//递归处理返回filedValue
			    	Object filedValue = copy(returnVal);
			    	method_set.invoke(target, filedValue);
			    }
			}
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return target;
	}
}

测试是否实现深拷贝的类:

package my.java.deepclone;

import com.alibaba.fastjson.JSONObject;

/**
 *  测试实现深拷贝了没有
	* @Description: TODO(这里用一句话描述这个类的作用) 
	* @author zhangmin
	* @date Feb 19, 2019 11:30:38 AM
 */
public class Test {

	public static void main(String[] args) {
		DetailAddr detailAddr = new DetailAddr("xiangxidizhi");
		Addr addr = new Addr("city", "dizhi",detailAddr);
		Student student = new Student("name", 11, addr);
		Student target = (Student) ObjectCopy.copy(student);
		System.out.println(JSONObject.toJSONString(target));
		
		/**
		 * 属性2次依赖 Student-》Addr
		 */
		target.getAddr().setCity("cccccc");
		System.out.println(JSONObject.toJSONString(target));
		System.out.println(JSONObject.toJSONString(student));
		
		/**
		 * 属性3次依赖 Student-》Addr-》DetailAddr
		 */
		DetailAddr detailAddr2 = new DetailAddr("222222");
		target.getAddr().setDetailAddr(detailAddr2);
		System.out.println(JSONObject.toJSONString(target));
		System.out.println(JSONObject.toJSONString(student));
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值