java反射
1、定义
反射是框架实现的核心,它可以操作类或对象的内部属性。通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。程序中一般的对象的类型都是在编译期就确定下来的,而 Java 反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。反射的核心是 JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先写代码的时候或编译期知道运行对象是谁,这就为封装框架提供了便利。
Java 反射主要提供的功能有,在运行时判断任意一个对象所属的类,在运行时构造任意一个类的对象,在运行时判断任意一个类所具有的成员变量和方法,运行时调用任意一个对象的方法(包含private方法)。例如当我们在使用 IDE时,当我们输入一个对象或类并想调用它的属性或方法时,一按点号,编译器就会自动列出它的属性或方法,这里就会用到反射。
反射可以用来开发框架,例如Spring这类框架首先要加载配置,然后根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射,运行时动态加载需要加载的对象。
比如 Struts 2 中会在 struts.xml 里去配置 Action
<action name="login" class="org.ScZyhSoft.test.action.SimpleLoginAction" method="execute"> <result>/shop/shop-index.jsp</result> <result name="error">login.jsp</result> </action>
配置文件与 Action 建立了一种映射关系,当 View 层发出请求时,请求会被 StrutsPrepareAndExecuteFilter 拦截,然后 StrutsPrepareAndExecuteFilter 会去动态地创建 Action 实例。比如我们请求 login.action,那么 StrutsPrepareAndExecuteFilter就会去解析struts.xml文件,检索action中name为login的Action,并根据class属性创建SimpleLoginAction实例,并用invoke方法来调用execute方法,这个过程离不开反射。
2、获得 Class 对象
- 使用 Class 类的 forName 静态方法
Class.forName(driver);
- 直接获取某一个对象的 class
Class<?> klass = int.class; Class<?> classInt = Integer.TYPE;
- 调用某个对象的 getClass() 方法,比如:
StringBuilder str = new StringBuilder("123"); Class<?> klass = str.getClass();
3、判断是否为某个类的实例
一般地,我们用 instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中 Class 对象的 isInstance() 方法来判断是否为某个类的实例,它是一个 native 方法
public native boolean isInstance(Object obj);
4、创建实例
通过反射来生成对象主要有两种方式。
使用Class对象的newInstance()方法来创建Class对象对应类的实例。
Class<?> c = String.class; Object str = c.newInstance();
使用Constructor构造器创建对象
Class<?> c = String.class; Constructor constructor = c.getConstructor(String.class); Object obj = constructor.newInstance("23333");
5、获取类的方法
- getDeclaredMethods 方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
public Method[] getDeclaredMethods() throws SecurityException
- getMethods 方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。
public Method[] getMethods() throws SecurityException
- getMethod 方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。
public Method getMethod(String name, Class<?>... parameterTypes)
6、反射调用例子
- 建立两个注解类
@Documented @Inherited @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) //放在方法前面 public @interface Action { int value() ; }
@Documented @Inherited @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) //放在方法的参数前面 public @interface Param { String value(); }
- 在service里面使用注解
@Transactional @Action(48500) public void addStocksAction(@Param("param1")Integer param1, @Param("param2")String param2 ) { System.out.println(param1); System.out.println(param2); }
- 在static代码块中加载类的方法到内存中
1 Method[] methods = SelfStockService.class.getDeclaredMethods(); 2 for(Method method : methods) { 3 if (method.isAnnotationPresent(Action.class)) { 4 Action action = method.getAnnotation(Action.class); 5 methodsMap.put(action.value(), method); 6 } 7 }
- 使用反射调用service类的方法,并给方法的参数赋值
1 public void dispatcherMethod(int action,HS2013 request) throws Throwable{ 2 Method method=methodsMap.get(action); 3 if(method!=null){ 4 Object[] parameterValues=new Object[method.getParameterCount()]; 5 Parameter[] parameters=method.getParameters(); 6 for(int i=0;i<method.getParameterCount();i++){ 7 String parameterName=parameters[i].getAnnotation(Param.class).value(); 8 if(parameters[i].getType()==String.class){ 9 parameterValues[i]=request.GetString(parameterName); 10 } 11 if(parameters[i].getType()==Integer.class){ 12 parameterValues[i]=request.GetInt(parameterName); 13 } 14 } 15 try{ 16 method.invoke(selfStockService,parameterValues); 17 } 18 //反射异常中重新抛出原来的targetException 19 catch (InvocationTargetException e){ 21 throw e.getTargetException(); 22 } 23 } 24 }

浙公网安备 33010602011771号