對於java的用戶而言,反射技術對於咱們使用來講是很是,下面仍是使用一個小的demo爲例子 1.首先定一個類:java
public class Zhangsan implements Man { @Override public void findObject() { System.out.println("oh , i find you."); } } 複製代碼
2.定一個測試類bash
public class TestMain { public static void main(String[] args) throws Throwable{ Method method = Class.forName("com.jdk14.demo.dynamic.myjdk.Man").getMethod("findObject"); Zhangsan zhangsan = new Zhangsan(); //1.Constructor for(int i=0; i < 16; i++) { method.invoke(zhangsan); } } 複製代碼
下圖就實現了對於對象的調用. markdown
方法的反射調用的實現源碼: 1.判斷是override,初始化是false,而後對於調用Class的訪問檢查. 2.判斷methodAccessor這個字段的是否爲空,第一次調用是空的,而後調用acquireMethodAccessor獲取,public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, Modifier.isStatic(modifiers) ? null : obj.getClass(), modifiers); } MethodAccessor ma = methodAccessor; // read volatile if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args); } 複製代碼
Method類中有一個屬性的root是頂部的Method,初始化是空, 而後就是從reflectionFactory#newMethodAccessor獲取到 MethodAccessor,ide
private MethodAccessor acquireMethodAccessor() { // First check to see if one has been created yet, and take it // if so MethodAccessor tmp = null; if (root != null) tmp = root.getMethodAccessor(); if (tmp != null) { methodAccessor = tmp; } else { // Otherwise fabricate one and propagate it up to the root tmp = reflectionFactory.newMethodAccessor(this); setMethodAccessor(tmp); } return tmp; } 複製代碼
能夠看出ReflectionFactory是裏面單例對象, 測試
經過RefectionFactory#newMethodAccessor方法,返回 DelegatingMethodAccessorImpl這個委託的調用類,裏面 開始代理實際是NativeMethodAccessorImplpublic MethodAccessor newMethodAccessor(Method method) { checkInitted(); if (Reflection.isCallerSensitive(method)) { Method altMethod = findMethodForReflection(method); if (altMethod != null) { method = altMethod; } } // use the root Method that will not cache caller class Method root = langReflectAccess.getRoot(method); if (root != null) { method = root; } if (noInflation && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) { return new MethodAccessorGenerator(). generateMethod(method.getDeclaringClass(),method.getName(), method.getParameterTypes(), method.getReturnType(), method.getExceptionTypes(), method.getModifiers()); } else { NativeMethodAccessorImpl acc = new NativeMethodAccessorImpl(method); DelegatingMethodAccessorImpl res = new DelegatingMethodAccessorImpl(acc); acc.setParent(res); return res; } } 複製代碼
而後看下NativeMethodAccessorImpl#invoke方法,這裏是JNI調用方式,這裏涉及一個概念,調用的膨脹閾值,是ReflectionFactory中inflationThreshold字段,默認是15,當反射調用大於15次,就是經過MethodAccessorGenerator#generateMethod底層是經過ClassFileAssembler這個類生成字節碼,這樣直接調用方法調用,效率要比Native要高,可是換來是生成class文件,這就是空間換取時間,經過設置parent#setdelegate方法,能夠動態替換NativeMethodAccessorImpl爲生成的MethodAccessorImpl.ui
public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException { // We can't inflate methods belonging to vm-anonymous classes because // that kind of class can't be referred to by name, hence can't be // found from the generated bytecode. // numInvocations默認值是15 if (++numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) { MethodAccessorImpl acc = (MethodAccessorImpl) new MethodAccessorGenerator(). generateMethod(method.getDeclaringClass(), method.getName(), method.getParameterTypes(), method.getReturnType(), method.getExceptionTypes(), method.getModifiers()); parent.setDelegate(acc); } return invoke0(method, obj, args); } 複製代碼
反射調用膨脹也可用經過 -Dsun.reflect.noInflation=true,直接打開開關. -Dsun.reflect.inflationThreshold=20,設置膨脹次數.this
總結:
今天經過分析反射調用的源碼,一塊兒分析下反射調用過程,spa