反射实现java深度克隆
一、克隆
有时想得到对象的一个复制品,该复制品的实体是原对象实体的克隆。复制品实体的变化不会引起原对象实体发生变化,这样的复制品称为原对象实体的克隆对象或简称克隆。
1、浅复制(浅克隆)
概念:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
方法:类implements Cloneable,然后重写clone()方法,在clone()方法中调用super.clone()即可,没有其他操作了
2、深复制(深克隆)
概念:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
一、克隆的实现
1、通过java的序列化实现克隆,即先对原对象进行序列化,然后再反序列化得到目标对象。
2. 通过反射进行,通过反射,获取对象的内部数据域,然后将数据依次复制,不多说,先上代码
package Reflection;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DeepCloneUtil {
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InstantiationException {
Person p = new Person("zhanchi",26);
System.out.println(Person.num);
Person p2 = (Person) cloneObject(p);
System.out.println(p2.getName());
System.out.println(p2.getAge());
System.out.println(p.list == p2.list);
System.out.println(p2.list.get(0) == p2);
System.out.println(p.list.get(0) == p2);
System.out.println(Person.num);
}
private static List<Field> getAllFieads(Object o) {
List<Field> fields = new ArrayList<Field>();
if (null == o)
return fields;
Class<?> type = o.getClass();
do {
for (Field f : type.getDeclaredFields()) {
fields.add(f);
}
type = type.getSuperclass();
} while (null != type);
return fields;
}
public static boolean isSimpleObject(Object o) {
Class<?> type = o.getClass();
if (type.isPrimitive()) { // 基本类型
return true;
}
// 不可更改的变量类型 如 String,Long
if (type.equals(String.class))
return true;
if (type.equals(Long.class))
return true;
if(type.equals(Boolean.class))
return true;
if(type.equals(Short.class))
return true;
if(type.equals(Integer.class))
return true;
if(type.equals(Character.class))
return true;
if(type.equals(Float.class))
return true;
if(type.equals(Double.class))
return true;
if(type.equals(Byte.class))
return true;
return false;
}
public static Object cloneObject(Object o) throws IllegalArgumentException, IllegalAccessException, InstantiationException{
if(null == o)
return null;
// 使用Map保存原对象和副本对象之间的结构,防止被多次引用的对象重复重建
Map<Object,Object> map = new HashMap<Object,Object>();
return cloneObject(o,map);
}
private static Object cloneObject(Object o, Map<Object, Object> map)
throws IllegalArgumentException, IllegalAccessException,
InstantiationException {
if (null == o)
return null;
Object newInstance = null;
newInstance = map.get(o);
if (null != newInstance) {
return newInstance;
}
if(isSimpleObject(o))
return o;
// 数组类型
if(o.getClass().isArray()){
return cloneArray(o,map);
}
Class<?> type = o.getClass();
newInstance = type.newInstance();
map.put(o, newInstance);
cloneFields(o, newInstance, map);
return newInstance;
}
private static Object cloneArray(Object o,Map<Object, Object> map) throws IllegalArgumentException, IllegalAccessException, InstantiationException{
if(null == o)
return null;
if(!o.getClass().isArray()){
return cloneObject(o,map);
}
int len = Array.getLength(o);
Object array = Array.newInstance(o.getClass().getComponentType(), len);
map.put(o, array);
for(int i = 0; i < len; i++){
Array.set(array, i, cloneObject(Array.get(o, i),map));
}
return array;
}
private static void cloneFinalObject(Object object, Object newObject, Map<Object, Object> map)throws IllegalArgumentException, IllegalAccessException, InstantiationException{
if(object == null || newObject == null || object == newObject || !newObject.getClass().equals(newObject.getClass()))
return ;
// 对于final类型的变量
if(null != map.get(newObject)){
return;
}
map.put(newObject, newObject);
cloneFields(object, newObject, map);
return ;
}
private static void cloneFields(Object object, Object newObject,
Map<Object, Object> map) throws SecurityException,
IllegalArgumentException, IllegalAccessException,
InstantiationException {
if(null == object || null == newObject){
return ;
}
List<Field> fields = getAllFieads(object);
for (Field f : fields) {
// 静态变量过滤掉 或者final的变量
if(Modifier.isStatic(f.getModifiers()))
continue;
// 常量
if(Modifier.isFinal(f.getModifiers())){
cloneFinalObject(f.get(object),f.get(newObject),map);
}else{
f.setAccessible(true);
f.set(newObject, cloneObject(f.get(object), map));
}
}
}
}
class Person{
static int num = 0;
Person p;
final List<Person> list = new ArrayList<Person>();
String [] testString = new String[3];
public Person() {
num ++ ;
}
public Person(String name, int age) {
this.age=age;
this.name=name;
p = this;
testString[2] = name;
list.add(p);
list.add(new Person());
num ++ ;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString(){
return "["+this.name+" "+this.age+"]";
}
private String name;
private int age;
}
反射实现java深度克隆的更多相关文章
- Java 深度克隆 clone()方法重写 equals()方法的重写
1.为什么要重写clone()方法? 答案:Java中的浅度复制是不会把要复制的那个对象的引用对象重新开辟一个新的引用空间,当我们需要深度复制的时候,这个时候我们就要重写clone()方法. 2.为什 ...
- Java List的深度克隆
关于java List的深度克隆 List是java容器中最常用的顺序存储数据结构之一.有些时候我们将一组数据取出放到一个List对象中,但是可能会很多处程序要读取他或者是修改他.尤其是并发处理的话, ...
- 【转】Java如何克隆集合——深度拷贝ArrayList和HashSet
原文网址:http://blog.csdn.net/cool_sti/article/details/21658521 原英文链接:http://javarevisited.blogspot.hk/2 ...
- java中传值及引伸深度克隆的思考(说白了Java只能传递对象指针)
java中传值及引伸深度克隆的思考 大家都知道java中没有指针.难道java真的没有指针吗?句柄是什么?变量地址在哪里?没有地址的话简直不可想象! java中内存的分配方式有两种,一种是在堆中分配, ...
- java对象 深度克隆(不实现Cloneable接口)和浅度克隆
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt128 为什么需要克隆: 在实际编程过程中,我们常常要遇到这种情况:有一个对象 ...
- 如何复制一个java对象(浅克隆与深度克隆)
在项目中,有时候有一些比较重要的对象经常被当作参数传来传去,和C语言的值传递不同,java语言的传递都是引用传递,在任何一个地方修改了这个对象的值,就会导致这个对象在内存中的值被彻底改变.但是很多时候 ...
- Java中深度克隆和浅度克隆
一:使用目的: 就是为了快速构造一个和已有对象相同的副本.如果需要克隆对象,一般需要先创建一个对象,然后将原对象中的数据导入到新创建的对象中去,而不用根据已有对象进行手动赋值操作. 二:Object中 ...
- Java的深度克隆和浅度克隆
说到克隆,其实是个比较简单的概念,跟现实生活正的克隆一样,复制一个一模一样的对象出来.clone()这个方法是从Object继承下来的,一个对象要实现克隆,需要实现一个叫做Cloneable的接口,这 ...
- Java的赋值、浅克隆和深度克隆的区别
赋值 直接 = ,克隆 clone 假如说你想复制一个简单变量.很简单: int a= 5; int b= a; b = 6; 这样 a == 5, b == 6 不仅仅是int类型,其它七种原始数 ...
随机推荐
- 新概念英语(1-131)Don't be so sure
Lesson 131 Don't be so sure! 别那么肯定! Listen to the tape then answer this question. What's the problem ...
- Spring Security入门(3-1)Spring Security的登录页面定制
- JsonCPP库使用
1.使用环境DevC++ a.建立C++工程,并添加.\JsonCPP\jsoncpp-master\jsoncpp-master\src\lib_json中源文件到工程中. b.添加头文件路径 2. ...
- Oracle12c在Win10上的安装配置实践
1.环境 操作系统:Win10专业版(64位) 数据库:Oracle 12c Release 2(Version 12.2.0.1.0,64位) 2.下载Oracle12c oracle官网下载地址: ...
- SpringMVC(六):@RequestMapping下使用@RequestHeader绑定请求报头的属性值、@CookieValue绑定请求中的Cookie值
备注:我本地浏览器的报头(Request Header)信息如下: Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image ...
- UVA-10714 Ants---蚂蚁模拟
题目链接: https://vjudge.net/problem/UVA-10714 题目大意: 给你一个长为L厘米的木棍在上面有n只蚂蚁,蚂蚁的爬行时间均为1厘米/秒,两只蚂蚁先遇会立即调转方向,调 ...
- PHP性能优化利器:生成器 yield理解
如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生.但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明显.但是,生成 ...
- 【MySQL】通过Binary Log简单实现数据回滚(一)
一.前言 对,没错,我又水了好一阵子,深刻反思寄几.前段时间,工作项目上出于对excel等批量操作可能出现误操作的问题,要求提供一个能够根据操作批次进行数据回滚的能力.在开发的过程中接触到了MySQL ...
- dnslog搭建
为什么想重写这个呢,想说后面扫描ssrf和命令执行的时候,能快速改成自己想要的api,更容易修改一些. 工具改自:https://github.com/bugScanTeam/DNSLog 需要两个域 ...
- [SDOI2016]游戏
Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 123456789123456789. 有时,Alice 会 ...