java反射的常见方式
jopen
10年前
反射常用于DI(依赖注入)的框架,如:Spring,guice等,在程序启动时这些框架读取配置文件中定义的类名然后根据类名去实例化类。
Class<?> c=Class.forName("com.younchen.model.Student"); Student s=(Student) c.newInstance();
反射的方式常见的有 :传统的反射方式(上面的例子),代理方式 , 方法句柄 ,以下是三种的基本实现。
以调用一个类的私有方法为例:
Person类:
package com.younchen.ioc; public class People { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void getMoney(String money){ System.out.println("reciveMoney :"+money); } }
Manager类:
package com.younchen.ioc; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Method; public class Manager { // 通过反射方法执行 public Method getReflectMethod() { Class<?>[] params = new Class[] { People.class, String.class }; Method method = null; try { method = Manager.class.getDeclaredMethod("giveMoney", params); // 私有方法访问权限 method.setAccessible(true); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } return method; } // 通过方法句柄执行 public MethodHandle getMethodHandler() { MethodType mt = MethodType.methodType(void.class, People.class, String.class); MethodHandle mh = null; try { mh = MethodHandles.lookup().findVirtual(Manager.class, "giveMoney", mt); } catch (Exception ex) { ex.printStackTrace(); } return mh; } // 代理方式 public static class ProxyPerson { private ProxyPerson() { }; public static ProxyPerson makeProxy() { return new ProxyPerson(); } public void invoke(Manager manager, People people, String food) { manager.giveMoney(people, food); } } /** * 要执行的私有方法 */ private void giveMoney(People people, String money) { people.getMoney(money); } }
测试类:
package com.younchen.ioc; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TestMain { Manager manager=new Manager(); People people=new People(); String money="100$"; public void sendmoney(){ //sendByHandleMethod(); //sendByProxy(); sendByReflect(); } public void sendByProxy(){ System.out.println("通过代理执行"); Manager.ProxyPerson.makeProxy().invoke(manager,people,money ); } public void sendByReflect(){ try { System.out.println("通过反射执行"); Method mh= manager.getReflectMethod(); mh.invoke(manager,people,money); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void sendByHandleMethod(){ try { System.out.println("通过方法句柄执行"); manager.getMethodHandler().invokeExact(manager,people,money); } catch (Throwable e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { // TODO Auto-generated method stub TestMain t=new TestMain(); t.sendmoney(); } }
方法句柄的优势:
1.相比传统的反射方式方法句柄更加简洁,可维护性好。
2.跟方法句柄在恰当的上下文中对所有的方法都有访问权限,跟安全管理器没有冲突,而且与代理模式比起来,方法句柄方式不占用PermGen,因为代理模式需要保存要引用的类有时可能需要较多的PermGen.