从今天开始将不定期更新一篇文章搞懂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));
}
}