利用反射特性完成对象的拷贝

反射是jdk1.5之后提供的一种可以让我们在类运行时动态获得类信息的机制,在类加载时,任何一个java类都存在一个java.lang.Class对象,反射即将类中的成分反射成对应的类型(属性,方法,构造器,注解等)对象,就和类自身照镜子一样,通过这种机制和泛型的结合,我们可以实现对任意一种类型对象的拷贝,废话不多说,直接上代码

public class CopyDemo {

/**
* 实现任意对象的拷贝,返回的具体类型的对象
* @param <T>
* @param source
* @param t
* @return
*/
public static <T> T clone(Object source,Class<T> t) {
T obj = null;
try {
//基于目标类型实例化对象
obj = t.newInstance();

Field[] fields = t.getDeclaredFields();
for (Field f : fields) {
String fname = f.getName();
// 分别获取属性对应的setter/getter方法名称
String sname = "set" + fname.substring(0, 1).toUpperCase() + fname.substring(1);
String gname = "get" + fname.substring(0, 1).toUpperCase() + fname.substring(1);
//如果属性是boolean类型的,则get方法应该改成is
if("boolean".equals(f.getType().getCanonicalName())) {
gname = "is" + fname.substring(0, 1).toUpperCase() + fname.substring(1);
}
//获取方法对象
Method methodSet = t.getMethod(sname, f.getType());
Method methodGet = t.getMethod(gname);

methodSet.invoke(obj, methodGet.invoke(source));
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}

return obj;
}


public static void main(String[] args) {

Dog d = new Dog();
d.setId(1);
d.setName("旺财");
d.setAge(5);
d.setType("二哈");

Dog user = CopyDemo.clone(d, Dog.class);
System.out.println(user.getName());
}

}

开始分析代码:

   public static <T> T clone(Object source,Class<T> t)  传入任意类型的对象,转换成指定类型(Class<T> t),返回一个对应泛型的对象

      先利用传入的Class类对象,获取该类的新对象  obj = t.newInstance();  

接着就是再把原对象的属性值传给obj

先通过getDeclaredField()方法获取指定类中所有属性集合  Field[] fields = t.getDeclaredFields();

通过 

String sname = "set" + fname.substring(0, 1).toUpperCase() + fname.substring(1);
String gname = "get" + fname.substring(0, 1).toUpperCase() + fname.substring(1);

这两步操作,可以获得指定类非Boolean类型属性的set和get方法.

如果有Boolean类型的属性可以加上一个判断获得:

if("boolean".equals(f.getType().getCanonicalName())) {
gname = "is" + fname.substring(0, 1).toUpperCase() + fname.substring(1);
}

有了方法名后 我们就可以通过getMethod获得指定的方法了

Method methodSet = t.getMethod(sname, f.getType()); // set方法中有参数 所以出了方法名之外还有方法的参数类型来确定方法
Method methodGet = t.getMethod(gname);

最后先通过Object returnVal = methodGet.invoke(source) 来获得原对象某属性的值 

再用 methodSet(obj,returnVal) 将source某属性的值赋给obj对象里

最后的最后 将 obj对象返回

最后的最后的最后 , 附上运行截图

 

今天你学到东西了吗?!

posted @ 2020-08-02 15:26  安心敲代码就完事了  阅读(184)  评论(0编辑  收藏  举报