JAVA对象克隆

来源:互联网 发布:修改游戏充值数据 编辑:程序博客网 时间:2024/06/05 17:20

为什么需要克隆

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

途径

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

  • 方法映射
  • 序列化和反序列化
  • 实现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
原创粉丝点击