一. 先了解反射
1. JAVA反射机制是在运行状态中,对于任意一个类, 都能够知道这个类的所有属性和方法; 对于任意一个对象, 都能调用它的任意一个方法和属性. 这种通过对象动态获取类的信息以及动态调用对象的方法的功能称为java语言的反射机制(照镜子).
2. 动态语言和非动态语言的区别.
动态语言, 在程序运行时能够动态获取对象的信息, 包括修改对象的类型, 如javascript, python, ruby; 反之java, c#, c++都属于非动态语言,
如JavaScript中定义任何变量都不需要申明类型, 并且可以动态修改数据类型.
Var i = true;
i = "hello";
但是在java中提供了一种反省机制, 只需要获得一个对象就能通过该对象获取对象所属的类的信息(属性, 构造器, 方法, 父类, 父接口, 注解, 泛型…), 这个概念就称之为反射.
反射弥补了java的非动态语言的不足, 但是也破坏了java的封装性, 一般在框架开发的时经常使用到.
二. 反射入门
1. 反射所需要使用到的类都来自于
java.lang.*
java.lang.reflect.*
2. 在java中获得一个类的Class对象有三种方式
//方式一: 类名.class
Class clz = People.class;
//方式二: 对象.getClass()
People p = new People(); //先获取该类对象
Class clz2 = p.getClass() ;
//方式三: 类加载器 “类所在的完整包路径”
Class clz3 = Class.forName(“com.softeem.reflect.People”);
3. 反射中一些常用方法
// Class clz1 = Student.class;
//
// Student stu = new Student();
// Class clz2 = stu.getClass();
//不会对类进行初始化操作(静态成员不会被加载)
//Class clz3 = Student.class.getClassLoader().loadClass("com.softeem.dto.Student");
//会对类执行初始化操作
Class clz = Class.forName("com.softeem.dto.Student");
//System.out.println(clz3);
//利用Class实例化对象(前提是被实例化的对象所在类必须包含默认的无参构造器)
Object obj = clz.newInstance();
//获取类中属性(获取所有public)
Field[] fields = clz.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("-----------");
//获取类中的所有属性(包括私有)
fields = clz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
//获取其中某一个属性对象(sname)
Field f = clz.getDeclaredField("sname");
System.out.println(f.getType());//获取当前属性的类型(Class对象)
System.out.println(f.getModifiers());//获取当前属性的访问修饰符所表示的常量字段值
f.set(obj, "hello");//将当前属性所在对象的值设置为指定值
System.out.println(f.get(obj));//获取当前属性在指定对象上的值
System.out.println(f.getName());//获取属性名
/*********获取方法*********/
//获取当前类所在对象的所有public方法(包括父类)
Method[] methods = clz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//获取一个指定的方法(通过方法名,属性类型获取方法对象)
Method method = clz.getMethod("setSex",clz.getField("sex").getType());
//执行方法
method.invoke(obj, "未知");
Method method2 = clz.getMethod("getSex");
Object r = method2.invoke(obj);
System.out.println(r);
三. 反射实现对象拷贝
package com.softeem.example;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.softeem.dto.Student;
public class ObjectClone {
/**
* 根据提供的参数拷贝一个数据一致的对象
* @param target
* @return
*/
public static <T> T copy(Object source,Class<T> clz){
//获取指定对象的Class对象
// Class<T> clz = T;//Student.class
/* 为什么要多加一个参数Class<T> clz?
* 是因为泛型, 为了返回值直接是该对象, 而不是Object.
*/
T newObj = null;
try {
//根据class对象创建当前类型的实例(空对象)
newObj = clz.newInstance();
//获取当前类中包含的所有属性
Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
//拼接获取setter/getter方法的名称
String setMethodName = "set"+field.getName().substring(0, 1).toUpperCase()+field.getName().substring(1);
String getMethodName = "get"+field.getName().substring(0, 1).toUpperCase()+field.getName().substring(1);
//根据方法名称获取方法对象
Method method_set = clz.getMethod(setMethodName, field.getType());//setter方法
Method method_get = clz.getMethod(getMethodName);//getter方法
//执行源对象指定属性的getter方法,获取属性值
Object returnval = method_get.invoke(source);
//执行新对象的setter方法,将源对象的属性值设置给新对象
method_set.invoke(newObj, returnval);
}
} 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 newObj;
}
public static void main(String[] args) {
Student s = new Student(1,"孙悟空","男",18,"打铁");
Student stu = ObjectClone.copy(s, Student.class);
System.out.println(stu);
}
}