JAVA对象克隆

为什么需要克隆

当我们需要两个数据内容相同,但物理存储地址不同的对象时,就会用到对象了。
(简单点说,就是当你的数据操作需要得到新的保存,但又不想改变原数据时,这时,我们就需要创建这么一个新的对象)

途径

目前,有三种方法来实现对象的克隆

  • 方法映射
  • 序列化和反序列化
  • 实现Cloneable接口

粗暴上代码

方法映射克隆对象

/**
     * 通过方法映射克隆对象
     * 
     * @param t
     *            被克隆对象
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T clone(T t) {
        Class<? extends Object> c = t.getClass();
        Object newT = null;
        try {
            newT = c.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        Field[] fields = c.getDeclaredFields();
        for (Field f : fields) {
            f.setAccessible(true);
            Type type = f.getGenericType();
            String getName = type.equals(boolean.class) ? toBooleanGetMethod(f
                    .getName()) : "get" + toUpperCaseFirstOne(f.getName());
            String setName = "set"
                    + (type.equals(boolean.class) ? toBooleanSetMethod(f
                            .getName()) : toUpperCaseFirstOne(f.getName()));
            // System.out.println(type + "  " + f.getType() + "==" + setName
            // + "           " + "" + getName);
            Method getMethod;
            Method setMethod;
            Object value = null;
            try {
                setMethod = c.getMethod(setName, f.getType());
                getMethod = c.getMethod(getName);
                value = getMethod.invoke(t, new Object[] {});
                if (type.equals(String.class) || type.equals(int.class)
                        || type.equals(double.class) || type.equals(long.class)
                        || type.equals(boolean.class)
                        || type.equals(byte.class)) {// 基本类型
                    setMethod.invoke(newT, new Object[] { value });
                } else if (f.getType().isInterface()) {// 接口类型,默认为List
                    if (f.getType().getSimpleName().equals("List")) {
                        List<Object> list = (List<Object>) value;
                        List<Object> newList = new ArrayList<Object>();
                        for (Object object : list) {
                            newList.add(clone(object));
                        }
                        setMethod.invoke(newT, new Object[] { newList });
                    } else {
                        Log.e(TAG, "接口解析类型不明确");
                    }
                } else if (type.equals(array.class)) {// 数组
                    int length = Array.getLength(value);
                    Class<?> arr = value.getClass().getComponentType();
                    Object newArr = Array.newInstance(arr, length);
                    System.arraycopy(value, 0, newArr, 0, length);
                    setMethod.invoke(newT, new Object[] { newArr });
                } else if (type.getClass() instanceof Object) {// 自定义对象
                    setMethod.invoke(newT, new Object[] { clone(value) });
                } else {// 不明确对象
                    Log.e(TAG, "数据类型不明确");
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }

        }

        return (T) newT;
    }

    /**
     * 字符串的首字母转化成大写
     * 
     * @param s
     * @return
     */
    private static String toUpperCaseFirstOne(String s) {
        if (Character.isUpperCase(s.charAt(0)))
            return s;
        else
            return (new StringBuilder())
                    .append(Character.toUpperCase(s.charAt(0)))
                    .append(s.substring(1)).toString();
    }

    /**
     * 获取布尔类型的get方法命名
     * 
     * @param s
     * @return
     */
    public static String toBooleanGetMethod(String s) {
        if (s.length() > 2 && s.substring(0, 2).equalsIgnoreCase("is")) {
            return new StringBuilder().append("is")
                    .append(Character.toUpperCase(s.charAt(2)))
                    .append(s.length() == 3 ? "" : s.substring(3)).toString();
        } else
            return new StringBuilder().append("is")
                    .append(Character.toUpperCase(s.charAt(0)))
                    .append(s.length() > 1 ? s.substring(1) : "").toString();

    }

    /**
     * 获取布尔类型的set方法命名
     * 
     * @param s
     * @return
     */
    public static String toBooleanSetMethod(String s) {
        String str = "";
        if (s.length() > 2 && s.substring(0, 2).equalsIgnoreCase("is")) {
            str = new StringBuilder()
                    .append(Character.toUpperCase(s.charAt(2)))
                    .append(s.length() == 3 ? "" : s.substring(3)).toString();
        } else
            str = toUpperCaseFirstOne(s);
        return str;
    }

序列化反序列化克隆

    /**
     * 通过序列化和反序列化 实现克隆(克隆:不同资源物理地址、相同资源内容的对象)
     * 
     * @param t
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T cloneBySerializable(T t) {
        try {
            if (t != null) {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(baos);
                oos.writeObject(t);
                oos.close();
                ByteArrayInputStream bais = new ByteArrayInputStream(
                        baos.toByteArray());
                ObjectInputStream ois = new ObjectInputStream(bais);
                t = (T) ois.readObject();
                ois.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "通过序列化克隆IO异常!");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            Log.e(TAG, "通过序列化克隆未找到数据类型!");
        }

        return t;
    }

实现Cloneable接口

这里,有必要提到的是深浅克隆,白话点说:

  • 浅克隆:也就是只克隆了这个实例,而其子对象是没有克隆的
  • 深克隆:克隆了这个实例以及他的子对象

来个例子(以下是copy的例子,不要告诉别人):

重点关注下方clone()方法的注释

Company.class

public class Company implements Cloneable{

    private User user;

    private String address;

    public Company(User user, String address) {
        super();
        this.user = user;
        this.address = address;
    }

//省去get set..

    @Override
    protected Object clone() throws CloneNotSupportedException {
    //注意这里,这里实现了子对象user的克隆,这就是所谓的深克隆

        Company company = (Company) super.clone();
    //如果没执行这句,就称之为浅克隆,是不是so easy?
        company.user = (User) company.getUser().clone();
        return company;
    }


}

User.class

public class User implements Cloneable{

    private String username;

    private String password;

    public User(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }


    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

THE END

上个工具的完整的代码

package com.stefan.afccutil.mapping;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import android.R.array;
import android.util.Log;

public class CloneUtil {
    private final static String TAG = CloneUtil.class.getClass()
            .getSimpleName();

    /**
     * 通过方法映射克隆对象
     * 
     * @param t
     *            被克隆对象
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T clone(T t) {
        Class<? extends Object> c = t.getClass();
        Object newT = null;
        try {
            newT = c.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        Field[] fields = c.getDeclaredFields();
        for (Field f : fields) {
            f.setAccessible(true);
            Type type = f.getGenericType();
            String getName = type.equals(boolean.class) ? toBooleanGetMethod(f
                    .getName()) : "get" + toUpperCaseFirstOne(f.getName());
            String setName = "set"
                    + (type.equals(boolean.class) ? toBooleanSetMethod(f
                            .getName()) : toUpperCaseFirstOne(f.getName()));
            // System.out.println(type + "  " + f.getType() + "==" + setName
            // + "           " + "" + getName);
            Method getMethod;
            Method setMethod;
            Object value = null;
            try {
                setMethod = c.getMethod(setName, f.getType());
                getMethod = c.getMethod(getName);
                value = getMethod.invoke(t, new Object[] {});
                if (type.equals(String.class) || type.equals(int.class)
                        || type.equals(double.class) || type.equals(long.class)
                        || type.equals(boolean.class)
                        || type.equals(byte.class)) {// 基本类型
                    setMethod.invoke(newT, new Object[] { value });
                } else if (f.getType().isInterface()) {// 接口类型,默认为List
                    if (f.getType().getSimpleName().equals("List")) {
                        List<Object> list = (List<Object>) value;
                        List<Object> newList = new ArrayList<Object>();
                        for (Object object : list) {
                            newList.add(clone(object));
                        }
                        setMethod.invoke(newT, new Object[] { newList });
                    } else {
                        Log.e(TAG, "接口解析类型不明确");
                    }
                } else if (type.equals(array.class)) {// 数组
                    int length = Array.getLength(value);
                    Class<?> arr = value.getClass().getComponentType();
                    Object newArr = Array.newInstance(arr, length);
                    System.arraycopy(value, 0, newArr, 0, length);
                    setMethod.invoke(newT, new Object[] { newArr });
                } else if (type.getClass() instanceof Object) {// 自定义对象
                    setMethod.invoke(newT, new Object[] { clone(value) });
                } else {// 不明确对象
                    Log.e(TAG, "数据类型不明确");
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }

        }

        return (T) newT;
    }

    /**
     * 字符串的首字母转化成大写
     * 
     * @param s
     * @return
     */
    private static String toUpperCaseFirstOne(String s) {
        if (Character.isUpperCase(s.charAt(0)))
            return s;
        else
            return (new StringBuilder())
                    .append(Character.toUpperCase(s.charAt(0)))
                    .append(s.substring(1)).toString();
    }

    /**
     * 获取布尔类型的get方法命名
     * 
     * @param s
     * @return
     */
    public static String toBooleanGetMethod(String s) {
        if (s.length() > 2 && s.substring(0, 2).equalsIgnoreCase("is")) {
            return new StringBuilder().append("is")
                    .append(Character.toUpperCase(s.charAt(2)))
                    .append(s.length() == 3 ? "" : s.substring(3)).toString();
        } else
            return new StringBuilder().append("is")
                    .append(Character.toUpperCase(s.charAt(0)))
                    .append(s.length() > 1 ? s.substring(1) : "").toString();

    }

    /**
     * 获取布尔类型的set方法命名
     * 
     * @param s
     * @return
     */
    public static String toBooleanSetMethod(String s) {
        String str = "";
        if (s.length() > 2 && s.substring(0, 2).equalsIgnoreCase("is")) {
            str = new StringBuilder()
                    .append(Character.toUpperCase(s.charAt(2)))
                    .append(s.length() == 3 ? "" : s.substring(3)).toString();
        } else
            str = toUpperCaseFirstOne(s);
        return str;
    }

    /**
     * 通过序列化和反序列化 实现克隆(克隆:不同资源物理地址、相同资源内容的对象)
     * 
     * @param t
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T cloneBySerializable(T t) {
        try {
            if (t != null) {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(baos);
                oos.writeObject(t);
                oos.close();
                ByteArrayInputStream bais = new ByteArrayInputStream(
                        baos.toByteArray());
                ObjectInputStream ois = new ObjectInputStream(bais);
                t = (T) ois.readObject();
                ois.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "通过序列化克隆IO异常!");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            Log.e(TAG, "通过序列化克隆未找到数据类型!");
        }

        return t;
    }
}

希望能够帮到你,有错误请及时指出,谢谢

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值