ReflectUitls类的编写和对反射机制的解析
反射相关的类
反射相关的类,最基本的当然是Class类。
获取了Class对象之后,就可以接着生成对象实例、调用方法、查看字段等等。
字段(Field)、方法(Method)和构造方法(Constructor<T>)各有相应的类来表示,它们共同继承于java.lang.reflect.AccessibleObject类:
这三个类共同实现的还有Member接口:
获取字段、方法和构造方法时,需要调用Class类的getXXX()和getDeclearedXXX()方法,需要注意二者区别。
比如对于方法:
getMethods();//获取public (包括父类中的)
getDeclaredMethods();//获取本类声明(包括各种修饰符public、private)
相关博文:Java中的反射机制(一)
API 文档:http://docs.oracle.com/javase/7/docs/api/
访问权限相关
利用反射,可以访问一些SDK、API中的私有方法。
访问私有方法有一个关键点:
setAccessible(true); // 抑制Java对修饰符的检查
这个方法是AccessibleObject类中的。
前面说过,它是Field、Method和Constructor<T>的共同基类。
正常情况下,调用isAccessible()返回的都是false,无论你的方法是public还是private。
这是因为这个accessible的flag是JVM用来限制是否可以直接访问,默认情况下是需要进行访问修饰符的检查的,所以flag为false,即不能直接访问。
当这个flag设置为true,表明可以直接访问,不经过访问修饰符的检查。
辅助类中用于调用私有方法的接口:
/**
* 调用私有方法
*
* @param obj
* 调用类对象
* @param methodName
* 方法名
* @param paramTypes
* 参数类型
* @param params
* 参数
* @return
* @throws Exception
*/
public static Object invokePrivateMethod(Object obj, String methodName,
Class<?>[] paramTypes, Object[] params) throws Exception {
Object value = null;
Class<?> cls = obj.getClass();
// 注意不要用getMethod(),因为getMethod()返回的都是public方法
Method method = cls.getDeclaredMethod(methodName, paramTypes);
method.setAccessible(true);// 抑制Java的访问控制检查
value = method.invoke(obj, params);
return value;
}
访问修饰符
对访问修饰符的获取可以通过Member接口的getModifiers()方法,该方法返回一个整型值,整型值是一系列的修饰符位操作组合的结果。
用Modifier类可以解析这个整型值中包含的修饰符信息。
/**
* 获取修饰符信息
*
* @param member
* @return
*/
private static String getModifiersInfo(Member member) {
StringBuilder sBuilder = new StringBuilder();
int modifiers = member.getModifiers();
sBuilder.append("\ngetModifiers: " + +modifiers + ", ");// 得到修饰符编码
sBuilder.append("\nisPublic: " + Modifier.isPublic(modifiers) + ", ");
sBuilder.append("\nisPrivate: " + Modifier.isPrivate(modifiers) + ", ");
sBuilder.append("\nisStatic: " + Modifier.isStatic(modifiers) + ", ");
sBuilder.append("\nisFinal: " + Modifier.isFinal(modifiers) + ", ");
sBuilder.append("\nisAbstract: " + Modifier.isAbstract(modifiers));
return sBuilder.toString();
}
包装类与原生数据类型
相关博文: Java 包装类 自动装箱和拆箱
写了一个调用静态方法的辅助类,我本来是这么写的:
/*
* wrong:
* public static Object invokePublicStaticMethod(String className,
* String methodName, Object[] params) throws Exception {
*
* Class<?> cls = Class.forName(className);
* Class<?>[] paramTypes = new Class<?>[params.length];
* for (int i = 0; i < params.length; ++i) {
* paramTypes[i] = params[i].getClass();
*
* }
* Method method = cls.getMethod(methodName, paramTypes);
* Object value = null;
* if (isPublicStatic(method)) {
* value = method.invoke(null, params);
* }
*
* return value;
* }
*/
意图是只传入参数数组,在内部自己根据参数获取类型数组,可以少传点参数,但是这样遇到了问题。
在Example类里写了这么三个测试方法:
public static void printSomething(String line) {
System.out.println(line);
}
public static int add(int a, int b) {
return a + b;
}
public static double getPi() {
return 3.14159d;
}
测试的时候发现参数是String类型的时候可以正常执行,但是参数如果是原生数据类型(int类型),用这个方法调用时就跑出了异常:
java.lang.NoSuchMethodException: com.mengdd.reflect.Example.add(java.lang.Integer, java.lang.Integer)
测试了一下:
Object[] array = new Object[] { 1, 2 };
System.out.println("getClass(): " + array[0].getClass());
System.out.println("Integer.TYPE: " + Integer.TYPE);
输出:
getClass(): class java.lang.Integer
Integer.TYPE: int
而那个用于测试的add()方法:
getReturnType: int
getParameterTypes: [int, int]
可见Integer和int被认为是两种类型,所以调用方法的时候,类型参数也还是从外部传入比较科学。
修改后的调用方法如下:
public static Object invokePublicStaticMethod(String className,
String methodName, Class<?>[] paramTypes, Object[] params)
throws Exception {
Class<?> cls = Class.forName(className);
Method method = cls.getMethod(methodName, paramTypes);
Object value = null;
if (isPublicStatic(method)) {
value = method.invoke(null, params);
}
return value;
}
测试代码:
Object result1 = ReflectUtils.invokePublicStaticMethod(
"com.mengdd.reflect.Example", "add", new Class<?>[] {
int.class, Integer.TYPE }, new Object[] { 1, 2 });
// int.class和Integer.TYPE都行
Assert.assertEquals(3, result1);
ReflectUtils类
ReflectUtils类完整代码如下:
package com.mengdd.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
/**
*
* @ClassName ReflectUtils
* @Description Reflection Helper class
*
* @author mengdandan
* @Date 2014年5月13日上午10:40:32
*
*/
public class ReflectUtils {
/**
* 创建类的实例,调用类的无参构造方法
*
* @param className
* @return
*/
public static Object newInstance(String className) {
Object instance = null;
try {
Class<?> clazz = Class.forName(className);
instance = clazz.newInstance();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (InstantiationException e) {
// if this Class represents an abstract class, an interface, an
// array class, a primitive type, or void; or if the class has no
// nullary constructor; or if the instantiation fails for some other
// reason.
e.printStackTrace();
}
catch (IllegalAccessException e) {
// if the class or its nullary constructor is not accessible
e.printStackTrace();
}
return instance;
}
/**
* 获取所有的public构造方法的信息
*
* @param className
* @return
*/
public static String getPublicConstructorInfo(String className) {
StringBuilder sBuilder = new StringBuilder();
try {
Class<?> clazz = Class.forName(className);
Constructor<?>[] constructors = clazz.getConstructors();
sBuilder.append(getConstructorInfo(constructors));
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
return sBuilder.toString();
}
/**
* 得到本类内声明的构造方法信息
*
* @param className
* @return
*/
public static String getDeclearedConstructorInfo(String className) {
StringBuilder sBuilder = new StringBuilder();
try {
Class<?> clazz = Class.forName(className);
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
sBuilder.append(getConstructorInfo(constructors));
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
return sBuilder.toString();
}
/**
* 获取public的字段信息
*
* @param className
* @return
*/
public static String getPublicFieldInfo(String className) {
StringBuilder sBuilder = new StringBuilder();
try {
Class<?> clazz = Class.forName(className);
Field[] fields = clazz.getFields();
sBuilder.append(getFieldInfo(fields));
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
return sBuilder.toString();
}
/**
* 获取本类内声明的字段信息
*
* @param className
* @return
*/
public static String getDecleardFieldInfo(String className) {
StringBuilder sBuilder = new StringBuilder();
try {
Class<?> clazz = Class.forName(className);
Field[] fields = clazz.getDeclaredFields();
sBuilder.append(getFieldInfo(fields));
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
return sBuilder.toString();
}
/**
* 得到所有public方法信息
*
* @param className
* @return
*/
public static String getPublicMethodInfos(String className) {
StringBuilder sBuilder = new StringBuilder();
try {
Class<?> clazz = Class.forName(className);
Method[] methods = clazz.getMethods();// 得到所有的public方法,包括从基类继承的
sBuilder.append(getMethodInfo(methods));
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
return sBuilder.toString();
}
/**
* 得到类内声明的方法信息
*
* @param className
* @return
*/
public static String getDeclaredMethodInfos(String className) {
StringBuilder sBuilder = new StringBuilder();
try {
Class<?> clazz = Class.forName(className);
Method[] methods = clazz.getDeclaredMethods();// 得到本类声明的所有方法,包括私有方法
// clazz.getMethods(); 会返回所有public的方法,但是包括基类Object的方法
sBuilder.append(getMethodInfo(methods));
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
return sBuilder.toString();
}
/**
* 得到构造器信息
*
* @param constructor
* @return
*/
private static String getConstructorInfo(Constructor<?> constructor) {
StringBuilder sBuilder = new StringBuilder();
sBuilder.append("name: " + constructor.getName());
sBuilder.append("\ngetParameterTypes: "
+ Arrays.toString(constructor.getParameterTypes()));
return sBuilder.toString();
}
/**
* 将一组构造器的信息组成一个字符串返回
*
* @param constructors
* @return
*/
private static String getConstructorInfo(Constructor<?>[] constructors) {
StringBuilder sBuilder = new StringBuilder();
int i = 0;
for (Constructor<?> c : constructors) {
sBuilder.append("method: " + ++i + " : ");
sBuilder.append("\n" + getConstructorInfo(c));
sBuilder.append("\n");
}
return sBuilder.toString();
}
/**
* 获取字段信息,组成一个字符串返回
*
* @param field
* @return
*/
private static String getFieldInfo(Field field) {
StringBuilder sBuilder = new StringBuilder();
sBuilder.append("name: " + field.getName());
sBuilder.append("\ngetType: " + field.getType());
sBuilder.append(getModifiersInfo(field));
return sBuilder.toString();
}
/**
* 获取一组字段的信息,返回字符串
*
* @param fields
* @return
*/
private static String getFieldInfo(Field[] fields) {
StringBuilder sBuilder = new StringBuilder();
int i = 0;
for (Field field : fields) {
sBuilder.append("field: " + ++i + " : ");
sBuilder.append("\n" + getFieldInfo(field));
sBuilder.append("\n");
}
return sBuilder.toString();
}
/**
* 获取方法的信息,组成一个字符串返回
*
* @param method
* @return
*/
private static String getMethodInfo(Method method) {
StringBuilder sBuilder = new StringBuilder();
sBuilder.append("name: " + method.getName());
sBuilder.append("\ngetReturnType: " + method.getReturnType());
sBuilder.append("\ngetParameterTypes: "
+ Arrays.toString(method.getParameterTypes()));
sBuilder.append(getModifiersInfo(method));
return sBuilder.toString();
}
/**
* 获取一组方法的信息,组成一个字符串返回
*
* @param methods
* @return
*/
private static String getMethodInfo(Method[] methods) {
StringBuilder sBuilder = new StringBuilder();
int i = 0;
for (Method method : methods) {
sBuilder.append("method: " + ++i + " : ");
sBuilder.append("\n" + getMethodInfo(method));
sBuilder.append("\n");
}
return sBuilder.toString();
}
/**
* 获取修饰符信息
*
* @param member
* @return
*/
private static String getModifiersInfo(Member member) {
StringBuilder sBuilder = new StringBuilder();
int modifiers = member.getModifiers();
sBuilder.append("\ngetModifiers: " + +modifiers + ", ");// 得到修饰符编码
sBuilder.append("\nisPublic: " + Modifier.isPublic(modifiers) + ", ");
sBuilder.append("\nisPrivate: " + Modifier.isPrivate(modifiers) + ", ");
sBuilder.append("\nisStatic: " + Modifier.isStatic(modifiers) + ", ");
sBuilder.append("\nisFinal: " + Modifier.isFinal(modifiers) + ", ");
sBuilder.append("\nisAbstract: " + Modifier.isAbstract(modifiers));
return sBuilder.toString();
}
/**
* 是否是公用静态方法
*
* @param member
* @return
*/
private static boolean isPublicStatic(Member member) {
boolean isPS = false;
int mod = member.getModifiers();
isPS = Modifier.isPublic(mod) && Modifier.isStatic(mod);
return isPS;
}
/**
* 调用静态方法
*
* @param className
* @param methodName
* @param paramTypes
* @param params
* @return
* @throws Exception
*/
public static Object invokePublicStaticMethod(String className,
String methodName, Class<?>[] paramTypes, Object[] params)
throws Exception {
Class<?> cls = Class.forName(className);
Method method = cls.getMethod(methodName, paramTypes);
Object value = null;
if (isPublicStatic(method)) {
value = method.invoke(null, params);
}
return value;
}
/*
* wrong:
* public static Object invokePublicStaticMethod(String className,
* String methodName, Object[] params) throws Exception {
*
* Class<?> cls = Class.forName(className);
* Class<?>[] paramTypes = new Class<?>[params.length];
* for (int i = 0; i < params.length; ++i) {
* paramTypes[i] = params[i].getClass();
*
* }
* Method method = cls.getMethod(methodName, paramTypes);
* Object value = null;
* if (isPublicStatic(method)) {
* value = method.invoke(null, params);
* }
*
* return value;
* }
*/
/**
* 调用私有方法
*
* @param obj
* 调用类对象
* @param methodName
* 方法名
* @param paramTypes
* 参数类型
* @param params
* 参数
* @return
* @throws Exception
*/
public static Object invokePrivateMethod(Object obj, String methodName,
Class<?>[] paramTypes, Object[] params) throws Exception {
Object value = null;
Class<?> cls = obj.getClass();
// 注意不要用getMethod(),因为getMethod()返回的都是public方法
Method method = cls.getDeclaredMethod(methodName, paramTypes);
method.setAccessible(true);// 抑制Java的访问控制检查
value = method.invoke(obj, params);
return value;
}
}
测试类和测试代码:
package com.mengdd.reflect;
public class Example {
private String mFiledOne = null;
private int mCount = 0;
private double mNum = 6;
public int mPub = 4;
public Example() {
}
public Example(String filedOne, int count, double num) {
super();
this.mFiledOne = filedOne;
this.mCount = count;
this.mNum = num;
}
public String getFiledOne() {
return mFiledOne;
}
public void setFiledOne(String filedOne) {
this.mFiledOne = filedOne;
}
public int getCount() {
return mCount;
}
public void setCount(int count) {
this.mCount = count;
}
public double getNum() {
return mNum;
}
public void setNum(double num) {
this.mNum = num;
}
public static void printSomething(String line) {
System.out.println(line);
}
public static int add(int a, int b) {
return a + b;
}
public static double getPi() {
return 3.14159d;
}
@Override
public String toString() {
return "Example [mFiledOne=" + mFiledOne + ", mCount=" + mCount + "]";
}
private String tellSecret(String name, int num) {
String result = name + num + toString();
return result;
}
}
package com.mengdd.reflect;
import org.junit.Assert;
import org.junit.Test;
public class ReflectTest {
@Test
public void testNewInstance() {
Object object = ReflectUtils.newInstance("com.mengdd.reflect.Example");
Assert.assertNotNull(object);
}
@Test
public void testGetConstructorInfo() {
String result = ReflectUtils
.getPublicConstructorInfo("com.mengdd.reflect.Example");
System.out
.println("=============testGetConstructorInfo================");
System.out.println(result);
System.out
.println("===================================================");
Assert.assertNotNull(result);
}
@Test
public void testFieldInfos() {
String result = ReflectUtils
.getDecleardFieldInfo("com.mengdd.reflect.Example");
System.out.println("=============testFieldInfos================");
System.out.println(result);
System.out
.println("===================================================");
Assert.assertNotNull(result);
}
@Test
public void testMethodInfos() {
String result = ReflectUtils
.getDeclaredMethodInfos("com.mengdd.reflect.Example");
System.out.println("=============testMethodInfos================");
System.out.println(result);
System.out
.println("===================================================");
Assert.assertNotNull(result);
}
@Test
public void testPublicStaticInvocation() {
System.out
.println("=============test static invocation================");
try {
// 静态方法1
ReflectUtils.invokePublicStaticMethod("com.mengdd.reflect.Example",
"printSomething", new Class<?>[] { String.class },
new Object[] { "Hello World" });
// 静态方法2
Object result1 = ReflectUtils.invokePublicStaticMethod(
"com.mengdd.reflect.Example", "add", new Class<?>[] {
int.class, Integer.TYPE }, new Object[] { 1, 2 });
// int.class和Integer.TYPE都行
Assert.assertEquals(3, result1);
// 静态方法3
Object result2 = ReflectUtils.invokePublicStaticMethod(
"com.mengdd.reflect.Example", "getPi", new Class<?>[] {},
new Object[] {});
Assert.assertEquals(3.14159, result2);
}
catch (Exception e) {
e.printStackTrace();
System.out.println("Exception!");
}
System.out
.println("===================================================");
}
@Test
public void testPrivateInvocation() {
Example example = new Example("1", 5, 0);
Object secret = null;
try {
secret = ReflectUtils.invokePrivateMethod(example, "tellSecret",
new Class<?>[] { String.class, Integer.TYPE },
new Object[] { "Hello", 2 });
}
catch (Exception e) {
e.printStackTrace();
}
String expected = "Hello2Example [mFiledOne=1, mCount=5]";
Assert.assertEquals(expected, secret);
}
}
再补充一个反射工具类:
ReflectUtils
package com.hwhmd.core.report.jasper.bean;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
/**
* 反射工具类
* <p>Title: ReflectUtils</p>
* <p>Description: </p>
* @author xiayuxuanmin
* @date 2019年5月16日
*/
public class ReflectUtils {
/**
* 通过字段名从对象或对象的父类中得到字段的值
* @param object 对象实例
* @param fieldName 字段名
* @return 字段对应的值
* @throws Exception
*/
public static Object getValue(Object object, String fieldName) throws Exception {
if (object == null) {
return null;
}
if (StringUtils.isBlank(fieldName)) {
return null;
}
Field field = null;
Class<?> clazz = object.getClass();
for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(object);
} catch (Exception e) {
//这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
//如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
}
}
return null;
}
/**
* 通过字段名从对象或对象的父类中得到字段的值(调用字典的get方法)
* @param object 对象实例
* @param fieldName 字段名
* @return 字段对应的值
* @throws Exception
*/
public static Object getValueOfGet(Object object, String fieldName) throws Exception {
if (object == null) {
return null;
}
if (StringUtils.isBlank(fieldName)) {
return null;
}
Field field = null;
Class<?> clazz = object.getClass();
for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
//获得get方法
Method getMethod = pd.getReadMethod();
//执行get方法返回一个Object
return getMethod.invoke(object);
} catch (Exception e) {
//这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
//如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
}
}
return null;
}
/**
* 通过字段名从对象或对象的父类中得到字段的值(调用字典的get方法,可以取出复杂的对象的值)
* @param object 对象实例
* @param fieldName 字段名
* @return 字段对应的值
* @throws Exception
*/
public static Object getValueOfGetIncludeObjectFeild(Object object, String fieldName)
throws Exception {
if (object == null) {
return null;
}
if (StringUtils.isBlank(fieldName)) {
return null;
}
if(HashMap.class.equals(object.getClass())){
return ((Map)object).get(fieldName);
}
Field field = null;
Class<?> clazz = object.getClass();
for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
try {
if (fieldName.contains(".")) {
// 如:operatorUser.name、operatorUser.org.name,递归调用
String[] splitFiledName = fieldName.split("\\.");
return getValueOfGetIncludeObjectFeild(
getValueOfGetIncludeObjectFeild(object, splitFiledName[0]),
splitFiledName[1]);
}
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
//获得get方法
Method getMethod = pd.getReadMethod();
//执行get方法返回一个Object
return getMethod.invoke(object);
} catch (Exception e) {
//这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
//如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
}
}
return null;
}
/**
* 根据属性名获取属性值
* */
private Object getFieldValueByName(String fieldName, Object o) {
try {
String firstLetter = fieldName.substring(0, 1).toUpperCase();
String getter = "get" + firstLetter + fieldName.substring(1);
Method method = o.getClass().getMethod(getter, new Class[] {});
Object value = method.invoke(o, new Object[] {});
return value;
} catch (Exception e) {
System.out.println(e.getStackTrace());
return null;
}
}
/**
* 获取属性名数组
* */
private String[] getFiledName(Object o){
Field[] fields=o.getClass().getDeclaredFields();
String[] fieldNames=new String[fields.length];
for(int i=0;i<fields.length;i++){
System.out.println(fields[i].getType());
fieldNames[i]=fields[i].getName();
}
return fieldNames;
}
/**
* 获取属性类型(type),属性名(name),属性值(value)的map组成的list
*/
private List getFiledsInfo(Object o){
Field[] fields=o.getClass().getDeclaredFields();
String[] fieldNames=new String[fields.length];
List list = new ArrayList();
Map infoMap=null;
for(int i=0;i<fields.length;i++){
infoMap = new HashMap();
infoMap.put("type", fields[i].getType().toString());
infoMap.put("name", fields[i].getName());
infoMap.put("value", getFieldValueByName(fields[i].getName(), o));
list.add(infoMap);
}
return list;
}
/**
* 获取对象的所有属性值,返回一个对象数组
*/
public Object[] getFiledValues(Object o){
String[] fieldNames=this.getFiledName(o);
Object[] value=new Object[fieldNames.length];
for(int i=0;i<fieldNames.length;i++){
value[i]=this.getFieldValueByName(fieldNames[i], o);
}
return value;
}
/**
* 获取对象的get方法
*/
public static String convertToGetterMethodName(String fieldName) {
StringBuilder getterName = new StringBuilder("get");
getterName.append(fieldName.substring(0, 1).toUpperCase());
getterName.append(fieldName.substring(1));
return getterName.toString();
}
/**
* 获取对象的set方法
*/
public static String convertToSetterMethodName(String fieldName) {
StringBuilder setterName = new StringBuilder("set");
setterName.append(fieldName.substring(0, 1).toUpperCase());
setterName.append(fieldName.substring(1));
return setterName.toString();
}
}
来源:oschina
链接:https://my.oschina.net/u/2331760/blog/3068515