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
- java克隆对象
- java 中克隆对象
- java中的对象克隆
- 浅谈java 对象克隆
- java对象的克隆
- java对象克隆clone
- java 对象 克隆 clone
- Java clone()克隆对象
- java对象的克隆
- JAVA 对象克隆clone
- java对象的克隆
- java 对象的克隆
- java对象克隆简介
- 模拟Java对象克隆
- Java克隆对象
- Java对象深度克隆
- java对象克隆clone
- JAVA对象的克隆
- visual studio code 快捷键和问题
- Android线程池的相关内容
- msdntellyou下载windows系统
- BottomNavigationView的基础使用3
- 动态规划-乘积最大
- JAVA对象克隆
- android multidex异步加载
- 数据结构——并查集
- CSND_Ayo 自我介绍 [编码规范、编程语言、其它平台]
- linux常用命令
- 图像坐标:我想和世界坐标谈谈(A) 【计算机视觉学习笔记--双目视觉几何框架系列】
- 多线程安全问题
- 结构——链表
- BootStrap的Tooltip插件源码解析