Java对象克隆方法(浅克隆、深克隆)

浅克隆:顾名思义就是很表面的很表层的克隆,比如我们要克隆User对象,浅克隆只克隆他自身以及他包含的所有对象的引用地址。
深克隆:就是非浅克隆。克隆除自身以外所有的对象,包括自身所包含的所有对象实例。至于深克隆的层次,由具体的需求决定,也有“N层克隆”一说。

浅克隆:
1、使用Cloneable接口实现,步骤如下:
a. 让该类实现Java.lang.Cloneable接口;
b. 重写(override)Object类的clone()方法。

深克隆:
方法1:通过Cloneable接口实现,但这里必须类中所有的非基本类型域都实现Cloneable接口,才能实现深克隆,所以此方法不通用
方法2:通过串行化方式实现(克隆对象必须实现Serializable接口)
把对象写到流里的过程是串行化(Serilization)过程,但是在Java程序师圈子里又非常形象地称为“冷冻”或者“腌咸菜(picking)”过程;而把对象从流中读出来的并行化(Deserialization)过程则叫做 “解冻”或者“回鲜(depicking)”过程。
应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝,Java咸菜还可以回鲜。
在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜),再从流里读出来(把咸菜回鲜),便可以重建对象。

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public abstract class BeanUtil {
    @SuppressWarnings("unchecked")
    public static <T> T cloneTo(T src) throws RuntimeException {
        ByteArrayOutputStream memoryBuffer = new ByteArrayOutputStream();
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        T dist = null;
        try {
            out = new ObjectOutputStream(memoryBuffer);
            out.writeObject(src);
            out.flush();
            in = new ObjectInputStream(new         ByteArrayInputStream(memoryBuffer.toByteArray()));
            dist = (T) in.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (out != null)
                try {
                    out.close();
                    out = null;
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            if (in != null)
                try {
                    in.close();
                    in = null;
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
        }
        return dist;
    }
}

方法3:通过反射的方式实现(克隆对象必须是可序列化的)
即依次遍历克隆对象中的所有域,直至全部域均为基本类型为止

package com.example.xiaowang.clonetest;

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;

/**
 * Created by xiaowang on 17/3/9.
 */

public class CloneUtil {

    /**
     * 返回对象的所以属性 包括继承至父类的属性
     *
     * @param o
     * @return
     */
    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;
    }


    /**
     * 基于效率的考虑不需要进行深度复制的类型:包括基本类型和包装类
     *
     * @param o
     * @return
     */
    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;
    }


    /**
     * 没有对cloneAble接口进行限制
     *
     * @param o
     * @return
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    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;
    }

    /**
     * 克隆数组对象
     *
     * @param o
     * @param map
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     */
    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;
    }

    /**
     * 对于final类型的变量 如果其为引用, 则尽管引用的值不需要更改,但引用对象的数据还是需要填充的
     *
     * @param object
     * @param newObject
     * @param map
     * @return
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    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));
            }
        }
    }
}

方法4:通过Json转换的方式(克隆对象必须实现Serializable接口)

Bean bean1 = new Bean();
Bean bean2 = new Gson().fromJson(new Gson().toJson(bean1), new TypeToken<Bean>(){}.getType());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值