为什么需要克隆
当我们需要两个数据内容相同,但物理存储地址不同的对象时,就会用到对象了。
(简单点说,就是当你的数据操作需要得到新的保存,但又不想改变原数据时,这时,我们就需要创建这么一个新的对象)
途径
目前,有三种方法来实现对象的克隆
- 方法映射
- 序列化和反序列化
- 实现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;
}
}
希望能够帮到你,有错误请及时指出,谢谢