反射經常使用於DI(依賴注入)的框架,如:Spring,guice等,在程序啓動時這些框架讀取配置文件中定義的類名而後根據類名去實例化類。java
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類:ui
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); } }
測試類:this
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(); } }
方法句柄的優點:spa
1.相比傳統的反射方式方法句柄更加簡潔,可維護性好。代理
2.跟方法句柄在恰當的上下文中對全部的方法都有訪問權限,跟安全管理器沒有衝突,並且與代理模式比起來,方法句柄方式不佔用PermGen,由於代理模式須要保存要引用的類有時可能須要較多的PermGen.code