------- android培训、java培训、期待与您交流! ----------
反射(Reflection)
反射概述:(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的內部信息,并能直接操作任意对象的内部属性及方法。
Java反射机制主要提供了以下功能:
- 在运行时构造任意一个类的对象。
- 在运行时获取任意一个类所具有的成员变量和方法。
- 在运行时调用任意一个对象的方法(属性)。
- 生成动态代理。
反射的使用场景:在写框架(如Spring,hibernate,struts)底层代码会经常用到。
一、关于Class:(下文中clazz都为Class的对象)
① 理解Class:Class是一个类
- 对象照镜子后可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。
- 对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。
- Class 对象只能由系统建立对象。
- 一个类在 JVM 中只会有一个Class实例,每个类的实例都会记得自己是由哪个 Class 实例所生成。
② 获取Class的三种方式:
- 直接通过类名.class方式获取。 例: clazz=Person.class;
- 通过对象调用.getClass()方法来获取。 例: Object obj=new Person();clazz=obj.getClass();
- 通过Class.forName(全类名)方式获(较多使用)。例: String className="com.hanxing.lesson1";clazz=Class.forName(className);
③ 利用反射创建对象:
- 调用 Class 对象的 newInstance() 方法获取
- 调用 Constructor 对象的 newInstance(Object...args[])获取
④利用Class对象获取当前类的方法
- Method[]methods=clazz.getMethods();//不能获取私有private方法,能获取从父类继承的方法
- Method[]methods=clazz.getDeclaredMethods();//获取当前类声明的方法,包括private方法,不包括从类从父类继承的方法。
- Method method=clazz.getDeclaredMethods(String name,Class<?>... parameterTypes);//获取指定方法 例:clazz.get("getName",String.class);
- Method method=clazz.getMethod(String name,Class<?>... parameterTypes);//获取指定方法,不能获取私有private方法,能获取从父类继承的方法
- 执行方法 method1.invoke
(Object obj, Object... args);
若method1为私有的则调用SetAccessible(true)方法
⑤利用Class对象获取当前类的字段,Filed封装了字段的信息
1.Field[] fields=clazz.getDeclaredFields();\\获取字段的数组
2.Field field=clazz.getDeclaredField(String name);\\获取指定字段
3.Object value=field.get(new Person()); \\获取指定对象的指定字段的值
4.若该字段为私有的,需要调用SetAccessible(true)方法
二、关于类加载器ClassLoader
概述 : 类装载器是用来把类(class)装载进 JVM 的。JVM 规范定义了两种类型的类装载器:启动类装载器(bootstrap)和用户自定义装载器(user-defined class loader)。 JVM在运行时会产生3个类加载器组成的初始化加载器层次结构.
- Bootstap ClassLoader(引导类加载器):用C++编写的,是JVM自带的类装载器,负责Java平台核心库,用来装载核心类库。该加载器无法直接获取
- Extension CLassLoader(扩展类加载器):负责jdk_home/lib/ext目录下的jar包或 –Djava.ext.dirs 指定目录下的jar包装入工作库
- System ClassLoader(系统类加载器) 负责java –classpath 或 –Djava.class.path所指的目录下的类与jar包装入工作
package com.hanxing.lesson12;
import java.io.IOException;
import org.junit.Test;
public class TestClassLoader {
@Test
public void testClassLoader() throws ClassNotFoundException, IOException {
// 获取系统类加载器
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
System.out.println("1: " + classLoader);// sun.misc.Launcher$AppClassLoader@1372a1a
// 获取系统类加载器的父加载器(扩展类加载器)
classLoader = classLoader.getParent();
System.out.println("2: " + classLoader);// sun.misc.Launcher$ExtClassLoader@ad3ba4
// 获取扩展类加载器的父加载器
classLoader = classLoader.getParent();
System.out.println("3: " + classLoader); // null
// 测试当前类由那个加载器加载
ClassLoader classLoader1 = Class.forName(
"com.hanxing.lesson12.TestClassLoader").getClassLoader();
System.out.println("4: " + classLoader1);
// 测试jdk提供的类由哪个加载器加载
classLoader = Class.forName("java.lang.String").getClassLoader();
System.out.println("5: " + classLoader);
}
}
结果如下:
1: sun.misc.Launcher$AppClassLoader@ad3ba4 //表示系统类装载器实例化自类sun.misc.Launcher$AppClassLoader
2: sun.misc.Launcher$ExtClassLoader@126b249 //表示系统类装载器的parent实例化自类sun.misc.Launcher$ExtClassLoader
3: null //表示系统类装载器parent的parent为bootstrap,无法直接获取
4: sun.misc.Launcher$AppClassLoader@ad3ba4 //表示类用户创建的类是由AppCLassLoader装载的
5: null //表示jdk提供的类是由bootstrap装载的
三丶反射的应用举例
这是个工具类,里面提供了获取方法,执行方法,获取属性,设置属性值,获取泛型的类型等的一些静态方法.
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* 反射的 Utils 函数集合
* 提供访问私有变量, 获取泛型类型 Class, 提取集合中元素属性等 Utils 函数
* @author Administrator
*
*/
public class ReflectionUtils {
/**
* 通过反射, 获得定义 Class 时声明的父类的泛型参数的类型
* 如: public EmployeeDao extends BaseDao<Employee, String>
* @param clazz
* @param index
* @return
*/
@SuppressWarnings("unchecked")
public static Class getSuperClassGenricType(Class clazz, int index){
Type genType = clazz.getGenericSuperclass();
if(!(genType instanceof ParameterizedType)){
return Object.class;
}
Type [] params = ((ParameterizedType)genType).getActualTypeArguments();
if(index >= params.length || index < 0){
return Object.class;
}
if(!(params[index] instanceof Class)){
return Object.class;
}
return (Class) params[index];
}
/**
* 通过反射, 获得 Class 定义中声明的父类的泛型参数类型
* 如: public EmployeeDao extends BaseDao<Employee, String>
* @param <T>
* @param clazz
* @return
*/
@SuppressWarnings("unchecked")
public static<T> Class<T> getSuperGenericType(Class clazz){
return getSuperClassGenricType(clazz, 0);
}
/**
* 循环向上转型, 获取对象的 DeclaredMethod
* @param object
* @param methodName
* @param parameterTypes
* @return
*/
public static Method getDeclaredMethod(Object object, String methodName, Class<?>[] parameterTypes){
for(Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()){
try {
//superClass.getMethod(methodName, parameterTypes);
return superClass.getDeclaredMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
//Method 不在当前类定义, 继续向上转型
}
//..
}
return null;
}
/**
* 使 filed 变为可访问
* @param field
*/
public static void makeAccessible(Field field){
if(!Modifier.isPublic(field.getModifiers())){
field.setAccessible(true);
}
}
/**
* 循环向上转型, 获取对象的 DeclaredField
* @param object
* @param filedName
* @return
*/
public static Field getDeclaredField(Object object, String filedName){
for(Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()){
try {
return superClass.getDeclaredField(filedName);
} catch (NoSuchFieldException e) {
//Field 不在当前类定义, 继续向上转型
}
}
return null;
}
/**
* 直接调用对象方法, 而忽略修饰符(private, protected)
* @param object
* @param methodName
* @param parameterTypes
* @param parameters
* @return
* @throws InvocationTargetException
* @throws IllegalArgumentException
*/
public static Object invokeMethod(Object object, String methodName, Class<?> [] parameterTypes,
Object [] parameters) throws InvocationTargetException{
Method method = getDeclaredMethod(object, methodName, parameterTypes);
if(method == null){
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + object + "]");
}
method.setAccessible(true);
try {
return method.invoke(object, parameters);
} catch(IllegalAccessException e) {
System.out.println("不可能抛出的异常");
}
return null;
}
/**
* 直接设置对象属性值, 忽略 private/protected 修饰符, 也不经过 setter
* @param object
* @param fieldName
* @param value
*/
public static void setFieldValue(Object object, String fieldName, Object value){
Field field = getDeclaredField(object, fieldName);
if (field == null)
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
makeAccessible(field);
try {
field.set(object, value);
} catch (IllegalAccessException e) {
System.out.println("不可能抛出的异常");
}
}
/**
* 直接读取对象的属性值, 忽略 private/protected 修饰符, 也不经过 getter
* @param object
* @param fieldName
* @return
*/
public static Object getFieldValue(Object object, String fieldName){
Field field = getDeclaredField(object, fieldName);
if (field == null)
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
makeAccessible(field);
Object result = null;
try {
result = field.get(object);
} catch (IllegalAccessException e) {
System.out.println("不可能抛出的异常");
}
return result;
}
}