java 反射

一、一般 反射方法

 

   /**
     * is the class contains the given method or not
     * @param clz the class that to judge if contains the method
     * @param m the method to judge if in clz
     * @return true if contains else false
     */
    public static boolean isContainsMethod(Class<Object> clz, Method m) {
        if (clz == null || m == null) {
            return false;
        }
        try {
            clz.getDeclaredMethod(m.getName(), m.getParameterTypes());
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

    /**
     * invoke object method
     * @param target the object to run method
     * @param methodName method name
     * @return object
     */
    public static Object invoke(Object target, String methodName) {
        return invoke(target, methodName, null);
    }

    /**
     * invoke object method
     * @param target the object to run method
     * @param methodName method name
     * @param paramValues parameter values
     * @return object
     */
    @SuppressWarnings("unchecked")
    public static Object invoke(Object target, String methodName,
        Object[] paramValues) {
        Class[] parameterTypes = getClassArray(paramValues);
        return invoke(target, methodName, parameterTypes, paramValues);
    }

    /**
     * invoke object method
     * @param target the object to run method
     * @param methodName method name
     * @param paramTypes parameter types
     * @param paramValues parameter values
     * @return object
     */
    @SuppressWarnings("unchecked")
    public static Object invoke(Object target, String methodName,
        Class[] paramTypes, Object[] paramValues) {
        try {
            Class clazz = target.getClass();
            Method method = clazz.getDeclaredMethod(methodName, paramTypes);
            return invoke(target, method, paramValues);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * invoke the target object method
     * @param target the target object
     * @param method the method to execute
     * @param paramValues the method parameters
     * @return object of result
     */
    public static Object invoke(Object target, Method method,
        Object[] paramValues) {
        boolean accessible = method.isAccessible();
        try {
            method.setAccessible(true);
            if (Modifier.isStatic(method.getModifiers())) {
                return method.invoke(null, paramValues);
            } else {
                return method.invoke(target, paramValues);
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } finally {
            method.setAccessible(accessible);
        }
    }
    
    /**
     * judge if the object has the given method by name
     * @param obj the object to judge
     * @param methodName the method name
     * @param paramTypes the parameterTypes
     * @return true or false
     */
    @SuppressWarnings("unchecked")
    public static boolean hasMethod(Object obj, String methodName,
        Class[] paramTypes) {
        Class clazz = obj.getClass();
        try {
            clazz.getDeclaredMethod(methodName, paramTypes);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

    /**
     * invoke the target class method
     * @param clazz the clazz to run parameter
     * @param methodName the method to execute
     * @param paramValues the method parameters
     * @return object of result
     */
    @SuppressWarnings("unchecked")
    public static Object invokeStatic(Class clazz, String methodName,
        Object[] paramValues) {
        try {
            Class[] parameterTypes = getClassArray(paramValues);
            Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
            return invokeStatic(method, paramValues);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (SecurityException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * invoke the target class method
     * @param clazz the clazz to run parameter
     * @param methodName the method to execute
     * @param paramTypes the method parameter types
     * @param paramValues the method parameters
     * @return object of result
     */
    @SuppressWarnings("unchecked")
    public static Object invokeStatic(Class clazz, String methodName,
        Class[] paramTypes, Object[] paramValues) {
        try {
            Method method = clazz.getDeclaredMethod(methodName, paramTypes);
            return invokeStatic(method, paramValues);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (SecurityException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * invoke the target class method
     * @param clazz the clazz to run parameter
     * @param methodName the method to execute
     * @return object of result
     */
    @SuppressWarnings("unchecked")
    public static Object invokeStatic(Class clazz, String methodName) {
        try {
            Method method = clazz.getDeclaredMethod(methodName);
            return invokeStatic(method, null);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (SecurityException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * invoke the target class method
     * @param method the method to execute
     * @param paramValues the method parameters
     * @return object of result
     */
    public static Object invokeStatic(Method method, Object[] paramValues) {
        boolean accessible = method.isAccessible();
        try {
            method.setAccessible(true);
            if (Modifier.isStatic(method.getModifiers())) {
                return method.invoke(null, paramValues);
            } else {
                throw new RuntimeException(
                    "can not run none static class without object");
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } finally {
            method.setAccessible(accessible);
        }
    }

    /**
     * judge if the object has the given method by name
     * @param clazz the object to judge
     * @param methodName the method name
     * @param paramTypes the parameterTypes
     * @return true or false
     */
    @SuppressWarnings("unchecked")
    public static boolean hasStaticMethod(Class clazz, String methodName,
        Class[] paramTypes) {
        try {
            clazz.getDeclaredMethod(methodName, paramTypes);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

    /**
     * get class types according to the objects
     * @param objects the objects to get class
     * @return null if the array is null
     */
    @SuppressWarnings("unchecked")
    public static Class[] getClassArray(Object[] objects) {
        if (objects == null) {
            return null;
        }
        int arguments = objects.length;
        Class[] objectTypes = new Class[arguments];
        for (int i = 0; i < arguments; i++) {
            objectTypes[i] = objects[i].getClass();
        }
        return objectTypes;
    }
    /**
     * get the field's value of super class 
     * @param obj   the objects to get class
     * @param fieldName the field name of object
     * @return Object the object
     */
    public static Object getSuperClassFieldValue(Object obj, String fieldName) {
        if (null == obj || fieldName == null || fieldName.trim().length() == 0) {
            return null;
        }
        try {
            Field field = obj.getClass().getSuperclass().getDeclaredField(
                fieldName);
            field.setAccessible(true);
            return field.get(obj);
        } catch (NoSuchFieldException nsf) {
            throw new RuntimeException(nsf);
        } catch (IllegalAccessException iae) {
            throw new RuntimeException(iae);
        }
    }
    /**
     * get the field's value of object 
     * @param obj   the objects to get class
     * @param fieldName the field name of object
     * @return Object the object
     */
    public static Object getFieldValue(Object obj, String fieldName) {
        if (null == obj || fieldName == null || fieldName.trim().length() == 0) {
            return null;
        }
        try {
            Field field = obj.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(obj);
        } catch (NoSuchFieldException nsf) {
            throw new RuntimeException(nsf);
        } catch (IllegalAccessException iae) {
            throw new RuntimeException(iae);
        }
    }
    /**
     * set the value of field 
     * @param obj   the objects to get class
     * @param fieldName the field name of object
     * @param value the vaule to set
     */
    public static void setFieldValue(Object obj, String fieldName, Object value) {
        if (null == obj) {
            throw new IllegalArgumentException("Object is null");
        }
        if (fieldName == null || fieldName.trim().length() == 0) {
            throw new IllegalArgumentException("Field name is null");
        }
        try {
            Field field = obj.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(obj, value);
        } catch (NoSuchFieldException nsf) {
            throw new RuntimeException(nsf);
        } catch (IllegalAccessException iae) {
            throw new RuntimeException(iae);
        }
    }
    
 
    public static Object getInstance(Class< ? > cls) {
        Constructor< ? > constructor;
        Object obj = null;
        try {
            constructor = cls.getDeclaredConstructor();
            constructor.setAccessible(true);
            obj = constructor.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

二、反射 父类 属性 方法

父类与子类

/**
 * 父类
 * @author syh
 *
 */

public class Parent {

	public String publicField  = "1";
	
	String defaultField = "2"; 
	
	protected String protectedField = "3";
	
	private String privateField = "4" ;
	
	public void publicMethod() {
		System.out.println("publicMethod...");
	}
	
	void defaultMethod() {
		System.out.println("defaultMethod...");
	}
	
	protected void protectedMethod() {
		System.out.println("protectedMethod...");
	}
	
	private void privateMethod() {
		System.out.println("privateMethod...");
	}
	
}




/**
 * 子类
 * @author syh
 *
 */

public class Son extends Parent{

}

 

  反射父类的属性方法

import java.lang.reflect.Field;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 方法类
 * @author syh
 *
 */

public class ReflectionUtils {

	/**
	 * 循环向上转型, 获取对象的 DeclaredMethod
	 * @param object : 子类对象
	 * @param methodName : 父类中的方法名
	 * @param parameterTypes : 父类中的方法参数类型
	 * @return 父类中的方法对象
	 */
	
	public static Method getDeclaredMethod(Object object, String methodName, Class<?> ... parameterTypes){
		Method method = null ;
		
		for(Class<?> clazz = object.getClass() ; clazz != Object.class ; clazz = clazz.getSuperclass()) {
			try {
				method = clazz.getDeclaredMethod(methodName, parameterTypes) ;
				return method ;
			} catch (Exception e) {
				//这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
				//如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
			
			}
		}
		
		return null;
	}
	
	/**
	 * 直接调用对象方法, 而忽略修饰符(private, protected, default)
	 * @param object : 子类对象
	 * @param methodName : 父类中的方法名
	 * @param parameterTypes : 父类中的方法参数类型
	 * @param parameters : 父类中的方法参数
	 * @return 父类中方法的执行结果
	 */
	
	public static Object invokeMethod(Object object, String methodName, Class<?> [] parameterTypes,
			Object [] parameters) {
		//根据 对象、方法名和对应的方法参数 通过反射 调用上面的方法获取 Method 对象
		Method method = getDeclaredMethod(object, methodName, parameterTypes) ;
		
		//抑制Java对方法进行检查,主要是针对私有方法而言
		method.setAccessible(true) ;
		
			try {
				if(null != method) {
					
					//调用object 的 method 所代表的方法,其方法的参数是 parameters
					return method.invoke(object, parameters) ;
				}
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		
		return null;
	}

	/**
	 * 循环向上转型, 获取对象的 DeclaredField
	 * @param object : 子类对象
	 * @param fieldName : 父类中的属性名
	 * @return 父类中的属性对象
	 */
	
	public static Field getDeclaredField(Object object, String fieldName){
		Field field = null ;
		
		Class<?> clazz = object.getClass() ;
		
		for(; clazz != Object.class ; clazz = clazz.getSuperclass()) {
			try {
				field = clazz.getDeclaredField(fieldName) ;
				return field ;
			} catch (Exception e) {
				//这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
				//如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
				
			} 
		}
	
		return null;
	}	
	
	/**
	 * 直接设置对象属性值, 忽略 private/protected 修饰符, 也不经过 setter
	 * @param object : 子类对象
	 * @param fieldName : 父类中的属性名
	 * @param value : 将要设置的值
	 */
	
	public static void setFieldValue(Object object, String fieldName, Object value){
	
		//根据 对象和属性名通过反射 调用上面的方法获取 Field对象
		Field field = getDeclaredField(object, fieldName) ;
		
		//抑制Java对其的检查
		field.setAccessible(true) ;
		
		try {
			//将 object 中 field 所代表的值 设置为 value
			 field.set(object, value) ;
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * 直接读取对象的属性值, 忽略 private/protected 修饰符, 也不经过 getter
	 * @param object : 子类对象
	 * @param fieldName : 父类中的属性名
	 * @return : 父类中的属性值
	 */
	
	public static Object getFieldValue(Object object, String fieldName){
		
		//根据 对象和属性名通过反射 调用上面的方法获取 Field对象
		Field field = getDeclaredField(object, fieldName) ;
		
		//抑制Java对其的检查
		field.setAccessible(true) ;
		
		try {
			//获取 object 中 field 所代表的属性值
			return field.get(object) ;
			
		} catch(Exception e) {
			e.printStackTrace() ;
		}
		
		return null;
	}
}

 

测试调用父类的各个属性方法

import static org.junit.Assert.*;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.junit.Test;

/**
 * 测试类,用JUnit4 进行测试
 * @author syh
 *
 */

public class ReflectionUtilsTest {

	/**
	 * 测试获取父类的各个方法对象
	 */
	
	@Test
	public void testGetDeclaredMethod() {
		
		Object obj = new Son() ;
		
		//获取公共方法名
		Method publicMethod = ReflectionUtils.getDeclaredMethod(obj, "publicMethod") ;
		System.out.println(publicMethod.getName());
		
		//获取默认方法名
		Method defaultMethod = ReflectionUtils.getDeclaredMethod(obj, "defaultMethod") ;
		System.out.println(defaultMethod.getName());
		
		//获取被保护方法名
		Method protectedMethod = ReflectionUtils.getDeclaredMethod(obj, "protectedMethod") ;
		System.out.println(protectedMethod.getName());
		
		//获取私有方法名
		Method privateMethod = ReflectionUtils.getDeclaredMethod(obj, "privateMethod") ;
		System.out.println(privateMethod.getName());
	}

	/**
	 * 测试调用父类的方法
	 * @throws Exception
	 */
	
	@Test
	public void testInvokeMethod() throws Exception {
		Object obj = new Son() ;
		
		//调用父类的公共方法
		ReflectionUtils.invokeMethod(obj, "publicMethod", null , null) ;
		
		//调用父类的默认方法
		ReflectionUtils.invokeMethod(obj, "defaultMethod", null , null) ;
		
		//调用父类的被保护方法
		ReflectionUtils.invokeMethod(obj, "protectedMethod", null , null) ;
		
		//调用父类的私有方法
		ReflectionUtils.invokeMethod(obj, "privateMethod", null , null) ;
	}

	/**
	 * 测试获取父类的各个属性名
	 */
	
	@Test
	public void testGetDeclaredField() {
		
		Object obj = new Son() ;
		
		//获取公共属性名
		Field publicField = ReflectionUtils.getDeclaredField(obj, "publicField") ;
		System.out.println(publicField.getName());
		
		//获取公共属性名
		Field defaultField = ReflectionUtils.getDeclaredField(obj, "defaultField") ;
		System.out.println(defaultField.getName());
		
		//获取公共属性名
		Field protectedField = ReflectionUtils.getDeclaredField(obj, "protectedField") ;
		System.out.println(protectedField.getName());
		
		//获取公共属性名
		Field privateField = ReflectionUtils.getDeclaredField(obj, "privateField") ;
		System.out.println(privateField.getName());
		
	}

	@Test
	public void testSetFieldValue() {
		
		Object obj = new Son() ;
		
		System.out.println("原来的各个属性的值: ");
		System.out.println("publicField = " + ReflectionUtils.getFieldValue(obj, "publicField"));
		System.out.println("defaultField = " + ReflectionUtils.getFieldValue(obj, "defaultField"));
		System.out.println("protectedField = " + ReflectionUtils.getFieldValue(obj, "protectedField"));
		System.out.println("privateField = " + ReflectionUtils.getFieldValue(obj, "privateField"));
		
		ReflectionUtils.setFieldValue(obj, "publicField", "a") ;
		ReflectionUtils.setFieldValue(obj, "defaultField", "b") ;
		ReflectionUtils.setFieldValue(obj, "protectedField", "c") ;
		ReflectionUtils.setFieldValue(obj, "privateField", "d") ;
		
		System.out.println("***********************************************************");
		
		System.out.println("将属性值改变后的各个属性值: ");
		System.out.println("publicField = " + ReflectionUtils.getFieldValue(obj, "publicField"));
		System.out.println("defaultField = " + ReflectionUtils.getFieldValue(obj, "defaultField"));
		System.out.println("protectedField = " + ReflectionUtils.getFieldValue(obj, "protectedField"));
		System.out.println("privateField = " + ReflectionUtils.getFieldValue(obj, "privateField"));
		
	}

	@Test
	public void testGetFieldValue() {
		
		Object obj = new Son() ;
		
		System.out.println("publicField = " + ReflectionUtils.getFieldValue(obj, "publicField"));
		System.out.println("defaultField = " + ReflectionUtils.getFieldValue(obj, "defaultField"));
		System.out.println("protectedField = " + ReflectionUtils.getFieldValue(obj, "protectedField"));
		System.out.println("privateField = " + ReflectionUtils.getFieldValue(obj, "privateField"));
	}

}

 

三、反射 修改 final field 常量

以[final int x=911] , [static final int x=912]为例,jdk1.6.0_16(为何如此版本详细,是因为下面还有个jdk的bug).

样例类:

class Test { 
 private final  int x=911;//modifiers:final->18,non-final->2
 static final private  int y=912;//modifiers:final->26,non-final->10 
 public int getX(){
  return x;
 }  
 public static int getY(){
  return y;
 } 
}
 

 

 Java中的final field意指常量,赋值一次,不可改变.编译器会对final field进行如下的优化:

e.g:

Test t=new Test();

凡是在程序中对t.x的引用,编译器都将以字面值911替换,getX()中的return x也会被替换成return 911;

所以就算在运行时你改变了x的值也无济于事,编译器对它们进行的是静态编译.

但是Test.class.getDeclaredField("x").getInt(t)除外;

 

那么如何在运行时改变final field x的值呢?

private final  int x=911;Field.modifiers为18,而private int x=911;Field.modifiers为2.

所以如果我们修改Field[Test.class.getDeclaredField("x")].modifiers由18[final]变为2[non-final],那么你就可以修改x的值了.

 Test tObj=new Test();  
 Field f_x=Test.class.getDeclaredField("x");  
  
  //修改modifiers 18->2
  Field f_f_x=f_x.getClass().getDeclaredField("modifiers");
  f_f_x.setAccessible(true);  
  f_f_x.setInt(f_x, 2/*non-final*/);
  
  f_x.setAccessible(true);
  f_x.setInt(tObj, 110);//改变x的值为110.  
  System.out.println("静态编译的x值:"+tObj.getX()+".------.运行时改变了的值110:"+f_x.getInt(tObj));
   
  f_x.setInt(tObj, 111);//你可以继续改变x的值为.  
  System.out.println(f_x.getInt(tObj));

但是想恢复原来的modifiers,f_f_x.setInt(f_x, 18/*final*/);这是无效的,因为Field只会初始化它的FieldAccessor引用一次.

 

在上面的过程中,我还发现了个jdk bug,你如果将上面的红色代码改为如下的代码:

f_f_x.setInt(f_x, 10 /*这个数值是static non-final modifiers,而x是non-static 的, 这样就会使f_x得到一个static FieldAccessor*/);那么会引发A fatal error has been detected by the Java Runtime Environment.并产生相应的err log文件.显然JVM没有对这种情况加以处理.我已提交to sun bug report site.
















 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值