黑马程序员-反射

 ------- android培训java培训、期待与您交流! ----------
反射(Reflection)

反射概述:(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的內部信息,并能直接操作任意对象的内部属性及方法。

Java反射机制主要提供了以下功能:

  1. 在运行时构造任意一个类的对象。
  2. 在运行时获取任意一个类所具有的成员变量和方法。
  3. 在运行时调用任意一个对象的方法(属性)。
  4. 生成动态代理。

反射的使用场景:在写框架(如Spring,hibernate,struts)底层代码会经常用到。

 

一、关于Class:(下文中clazz都为Class的对象)

①  理解Class:Class是一个类

  1. 对象照镜子后可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。
  2. 对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。
  3. Class 对象只能由系统建立对象。
  4. 一个类在 JVM 中只会有一个Class实例,每个类的实例都会记得自己是由哪个 Class 实例所生成。

  获取Class的三种方式:

  1. 直接通过类名.class方式获取。      例: clazz=Person.class;
  2. 通过对象调用.getClass()方法来获取。   例: Object obj=new Person();clazz=obj.getClass();
  3. 通过Class.forName(全类名)方式获(较多使用)。例: String  className="com.hanxing.lesson1";clazz=Class.forName(className);      

③  利用反射创建对象:

  1. 调用 Class 对象的 newInstance() 方法获取
  2. 调用 Constructor 对象的 newInstance(Object...args[])获取

④利用Class对象获取当前类的方法

  1. Method[]methods=clazz.getMethods();//不能获取私有private方法,能获取从父类继承的方法
  2. Method[]methods=clazz.getDeclaredMethods();//获取当前类声明的方法,包括private方法,不包括从类从父类继承的方法。
  3. Method method=clazz.getDeclaredMethods(String name,Class<?>... parameterTypes);//获取指定方法 例:clazz.get("getName",String.class);
  4. Method method=clazz.getMethod(String name,Class<?>... parameterTypes);//获取指定方法,不能获取私有private方法,能获取从父类继承的方法
  5. 执行方法 method1.invoke(Object obj, Object... args);
  6. 若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个类加载器组成的初始化加载器层次结构.

  1. Bootstap ClassLoader(引导类加载器):用C++编写的,是JVM自带的类装载器,负责Java平台核心库,用来装载核心类库。该加载器无法直接获取
  2. Extension CLassLoader(扩展类加载器):负责jdk_home/lib/ext目录下的jar包或 –Djava.ext.dirs 指定目录下的jar包装入工作库
  3. 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    //表示系统类装载器parentparentbootstrap,无法直接获取
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;
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值