溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么在java中利用invoke方法實現(xiàn)一個反射功能

發(fā)布時間:2021-01-11 14:51:06 來源:億速云 閱讀:171 作者:Leah 欄目:開發(fā)技術(shù)

怎么在java中利用invoke方法實現(xiàn)一個反射功能?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

首先給出invoke方法多態(tài)特性的演示代碼:

public class MethodInvoke {
 
	public static void main(String[] args) throws Exception {
		Method animalMethod = Animal.class.getDeclaredMethod("print");
		Method catMethod = Cat.class.getDeclaredMethod("print");
		
		Animal animal = new Animal();
		Cat cat = new Cat();
		animalMethod.invoke(cat);
		animalMethod.invoke(animal);
		
		catMethod.invoke(cat);
		catMethod.invoke(animal);
	}
	
}
 
class Animal {
	
	public void print() {
		System.out.println("Animal.print()");
	}
	
}
 
class Cat extends Animal {
	
	@Override
	public void print() {
		System.out.println("Cat.print()");
	}
	
}

代碼中,Cat類覆蓋了父類Animal的print()方法, 然后通過反射分別獲取print()的Method對象。最后分別用Cat和Animal的實例對象去執(zhí)行print()方法。其中animalMethod.invoke(animal)和catMethod.invoke(cat),示例對象的真實類型和Method的聲明Classs是相同的,按照預(yù)期打印結(jié)果;animalMethod.invoke(cat)中,由于Cat是Animal的子類,按照多態(tài)的特性,子類調(diào)用父類的的方法,方法執(zhí)行時會動態(tài)鏈接到子類的實現(xiàn)方法上。因此,這里會調(diào)用Cat.print()方法;而catMethod.invoke(animal)中,傳入的參數(shù)類型Animal是父類,卻期望調(diào)用子類Cat的方法,因此這一次會拋出異常。代碼打印結(jié)果為:

Cat.print()
Animal.print()
Cat.print()
Exception in thread "main" java.lang.IllegalArgumentException: object is not an instance of declaring class
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
 at java.lang.reflect.Method.invoke(Unknown Source)
 at com.wy.invoke.MethodInvoke.main(MethodInvoke.java:17)

接下來,我們來看看invoke()方法的實現(xiàn)過程。

 public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
 {
 if (!override) {
 if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
 Class<?> caller = Reflection.getCallerClass(1);
 
 checkAccess(caller, clazz, obj, modifiers);
 }
 }
 MethodAccessor ma = methodAccessor; // read volatile
 if (ma == null) {
 ma = acquireMethodAccessor();
 }
 return ma.invoke(obj, args);
 }

invoke()方法中主要分為兩部分:訪問控制檢查和調(diào)用MethodAccessor.invoke()實現(xiàn)方法執(zhí)行。

首先看一下訪問控制檢查這一塊的邏輯。第一眼看到這里的邏輯的時候,很容易搞不清楚是干嘛的。通俗來講就是通過方法的修飾符(public/protected/private/package),來判斷方法的調(diào)用者是否可以訪問該方法。這是java的基礎(chǔ)內(nèi)容,不過用代碼寫出來,一下子不容易想到。訪問控制檢查分為3步:

  1. 檢查override,如果override為true,跳過檢查;否則繼續(xù);

  2. 快速檢查,判斷該方法的修飾符modifiers是否為public,如果是跳過檢查;否則繼續(xù);

  3. 詳細(xì)檢查,通過方法的(protected/private/package)修飾符或方法的聲明類(例如子類可以訪問父類的protected方法)與調(diào)用者caller之間的關(guān)系,判斷caller是否有權(quán)限訪問該方法。

override屬性是Method的父類AccessibleObject中聲明的變量,使得程序可以控制是否跳過訪問權(quán)限的檢查。另外,Method的實例對象中,override屬性的初始值設(shè)置為false。

 public void setAccessible(boolean flag) throws SecurityException {
 SecurityManager sm = System.getSecurityManager();
 if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
 setAccessible0(this, flag);
 }
 
 private static void setAccessible0(AccessibleObject obj, boolean flag)
 throws SecurityException
 {
 if (obj instanceof Constructor && flag == true) {
 Constructor<?> c = (Constructor<?>)obj;
 if (c.getDeclaringClass() == Class.class) {
 throw new SecurityException("Can not make a java.lang.Class" +
   " constructor accessible");
 }
 }
 obj.override = flag;
 }

多說一句,F(xiàn)ield同樣繼承了AccessibleObject,且Field的override也是初始化為false的,也就是說并沒有按照變量的修飾符去初始化不同的值。但是我們在調(diào)用Field.set(Object obj, Object value)時,如果該Field是private修飾的,會因沒有訪問權(quán)限而拋出異常,因此必須調(diào)用setAccessible(true)。此處非常容易理解為因為變量是public的,所以override就被初始化為true。

invoke()方法中,訪問控制檢查之后,就是通過MethodAccessor.invoke()調(diào)用方法。再來看一下代碼:

 MethodAccessor ma = methodAccessor; // read volatile
 if (ma == null) {
 ma = acquireMethodAccessor();
 }
 return ma.invoke(obj, args);

這里的邏輯很簡單,首先將變量methodAccessor賦值給ma,在方法棧中保存一個可以直接引用的本地變量,如果methodAccessor不存在,調(diào)用acquireMethodAccessor()方法創(chuàng)建一個。

 private volatile MethodAccessor methodAccessor;
 private Method root;
 
 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;
 }
 
 void setMethodAccessor(MethodAccessor accessor) {
 methodAccessor = accessor;
 // Propagate up
 if (root != null) {
 root.setMethodAccessor(accessor);
 }
 }
 
 Method copy() {
 Method res = new Method(clazz, name, parameterTypes, returnType,
  exceptionTypes, modifiers, slot, signature,
  annotations, parameterAnnotations, annotationDefault);
 res.root = this;
 res.methodAccessor = methodAccessor;
 return res;
 }

綜合acquireMethodAccessor(),setMethodAccessor()以及copy()這三個方法,可以看到一個Method實例對象維護了一個root引用。當(dāng)調(diào)用Method.copy()進行方法拷貝時,root指向了被拷貝的對象。那么當(dāng)一個Method被多次拷貝后,調(diào)用一次setMethodAccessor()方法,就會將root引用所指向的Method的methodAccessor變量同樣賦值。例如:D -> C -> B -> A,其中X-> Y表示X = Y.copy(), 當(dāng)C對象調(diào)用setMethodAccessor()時,B和A都會傳播賦值methodAccessor, 而D的methodAccessor還是null。緊接著,當(dāng)D需要獲取methodAccessor而調(diào)用acquireMethodAccessor()時,D獲取root的methodAccessor, 那么D將和ABC持有相同的methodAccessor。

雖然Method中,通過維護root引用意圖使相同的方法始終保持只有一個methodAccessor實例,但是上述方法仍然無法保證相同的方法只有一個methodAccessor實例。例如通過copy()使ABCD保持關(guān)系:D -> C -> B -> A, 當(dāng)B對象調(diào)用setMethodAccessor()時,B和A都會賦值methodAccessor, 而C、D的methodAccessor還是null。這時D調(diào)用acquireMethodAccessor()時,D獲取root也就是C的methodAccessor,發(fā)現(xiàn)為空,然后就新創(chuàng)建了一個。從而出現(xiàn)了相同的方法中出現(xiàn)了兩個methodAccessor實例對象的現(xiàn)象。

在Class.getMethod()、Class.getDeclaredMethod()以及Class.getDeclaredMethod(String name, Class<?>... parameterTypes)方法中最終都會調(diào)用copy()方法來保障Method使用的安全性。 在比較極端加巧合的情況下,可能會引起類膨脹的問題,這就是接下來要講到的MethodAccessor的實現(xiàn)機制。

怎么在java中利用invoke方法實現(xiàn)一個反射功能

在前面代碼中,MethodAccessor的創(chuàng)建是通過反射工廠ReflectionFactory的newMethodAccessor(Method)方法來創(chuàng)建的。

 public MethodAccessor newMethodAccessor(Method method) {
 checkInitted();
 
 if (noInflation) {
 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;
 }
 }

其中, checkInitted()方法檢查從配置項中讀取配置并設(shè)置noInflation、inflationThreshold的值:

 private static void checkInitted() {
 if (initted) return;
 AccessController.doPrivileged(
 new PrivilegedAction<Void>() {
 public Void run() {
 
  if (System.out == null) {
  // java.lang.System not yet fully initialized
  return null;
  }
 
  String val = System.getProperty("sun.reflect.noInflation");
  if (val != null && val.equals("true")) {
  noInflation = true;
  }
 
  val = System.getProperty("sun.reflect.inflationThreshold");
  if (val != null) {
  try {
  inflationThreshold = Integer.parseInt(val);
  } catch (NumberFormatException e) {
  throw (RuntimeException)
  new RuntimeException("Unable to parse property sun.reflect.inflationThreshold").
   initCause(e);
  }
  }
 
  initted = true;
  return null;
 }
 });
 }

可以通過啟動參數(shù)-Dsun.reflect.noInflation=false -Dsun.reflect.inflationThreshold=15來設(shè)置:

怎么在java中利用invoke方法實現(xiàn)一個反射功能

結(jié)合字面意思及下面代碼理解,這兩個配置sun.reflect.noInflation是控制是否立即進行類膨脹,sun.reflect.inflationThreshold是設(shè)置類膨脹閾值。

創(chuàng)建MethodAccessor有兩種選擇,一種是當(dāng)sun.reflect.noInflation配置項為true時,ReflectionFactory利用MethodAccessor的字節(jié)碼生成類 MethodAccessorGenerator直接創(chuàng)建一個代理類,通過間接調(diào)用原方法完成invoke()任務(wù),具體實現(xiàn)稍后給出。MethodAccessor的另一種實現(xiàn)方式是,創(chuàng)建DelegatingMethodAccessorImpl 委托類,并將執(zhí)行invoke()方法的具體內(nèi)容交由NativeMethodAccessorImpl實現(xiàn),而NativeMethodAccessorImpl最終調(diào)用native方法完成invoke()任務(wù)。以下是NativeMethodAccessorImpl的invoke()方法實現(xiàn)。

 public Object invoke(Object obj, Object[] args) 
 throws IllegalArgumentException, InvocationTargetException
 {
 if (++numInvocations > ReflectionFactory.inflationThreshold()) {
 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);
 }
 
 private static native Object invoke0(Method m, Object obj, Object[] args);

可以看到,當(dāng)numInvocations數(shù)量大于配置項sun.reflect.inflationThreshold即類膨脹閾值時, 使用MethodAccessorGenerator創(chuàng)建一個代理類對象,并且將被委托的NativeMethodAccessorImpl的parent,也就是委托類DelegatingMethodAccessorImpl的委托類設(shè)置為這個生成的代理對象。這么說可能有點繞,下面用一幅圖表示這個過程。

怎么在java中利用invoke方法實現(xiàn)一個反射功能

總體來說,當(dāng)調(diào)用invoke()時,按照默認(rèn)配置,Method首先創(chuàng)建一個DelegatingMethodAccessorImpl對象,并設(shè)置一個被委托的NativeMethodAccessorImpl對象,那么method.invoke()就被轉(zhuǎn)換成DelegatingMethodAccessorImpl.invoke(),然后又被委托給NativeMethodAccessorImp.invoke()實現(xiàn)。當(dāng)NativeMethodAccessorImp.invoke()調(diào)用次數(shù)超過一定熱度時(默認(rèn)15次),被委托方又被轉(zhuǎn)換成代理類來實現(xiàn)。

之前提到過在極端情況下,同一個方法的Method對象存在多個不同拷貝拷貝時,可能存在多個MethodAccessor對象。那么當(dāng)多次調(diào)用后,必然會生成兩個重復(fù)功能的代理類。當(dāng)然,一般情況下,生成兩個代理類并沒有較大的影響。

其中代理類的具體字節(jié)碼實現(xiàn)過程較為復(fù)雜,大體思想是生成一個如下所示的類:

public class GeneratedMethodAccessor1 extends MethodAccessorImpl {
 
	public GeneratedMethodAccessor1 () {
	 super();
	}
	
	public Object invoke(Object obj, Object[] args)
	 throws IllegalArgumentException, InvocationTargetException 
	{
		if (!(obj instanceof Cat)) {
			throw new ClassCastException();
		}
		if (args != null && args.length != 0) {
			throw new IllegalArgumentException();
		}
		
		try {
			Cat cat = (Cat) obj;
			cat.print();
			return null;
		} catch (Throwable e) {
			throw new InvocationTargetException(e, "invoke error");
		}
	}
	
}

到目前為止,除了在代理的GeneratedMethodAccessor1 類中,方法的執(zhí)行有多態(tài)的特性,而NativeMethodAccessorImp的invoke()實現(xiàn)是在jdk中的完成的。接下來我們將目光移到NativeMethodAccessorImp的native方法invoke0();

openJDK下載地址

首先,在\jdk\src\share\native\sun\reflect路徑下找到NativeAccessors.c, 其中有Java_sun_reflect_NativeMethodAccessorImpl _invoke0()方法,根據(jù)JNI定義函數(shù)名的規(guī)則"包名_類名_方法名",這就是我們要找的native方法實現(xiàn)入口。

JNIEXPORT jobject JNICALL Java_sun_reflect_NativeMethodAccessorImpl_invoke0
(JNIEnv *env, jclass unused, jobject m, jobject obj, jobjectArray args)
{
 return JVM_InvokeMethod(env, m, obj, args);
}

方法調(diào)用JVM_InvokeMethod(), 一般以JVM_開頭的函數(shù)定義在jvm.cpp文件中,不熟悉的話可以通過頭文件jvm.h看出來。繼續(xù)追蹤,發(fā)現(xiàn)jvm.cpp文件位于spot\src\share\vm\prims文件夾下。

JVM_ENTRY(jobject, JVM_InvokeMethod(JNIEnv *env, jobject method, jobject obj, jobjectArray args0))
 JVMWrapper("JVM_InvokeMethod");
 Handle method_handle;
 if (thread->stack_available((address) &method_handle) >= JVMInvokeMethodSlack) {
 method_handle = Handle(THREAD, JNIHandles::resolve(method));
 Handle receiver(THREAD, JNIHandles::resolve(obj));
 objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0)));
 oop result = Reflection::invoke_method(method_handle(), receiver, args, CHECK_NULL);
 jobject res = JNIHandles::make_local(env, result);
 if (JvmtiExport::should_post_vm_object_alloc()) {
 oop ret_type = java_lang_reflect_Method::return_type(method_handle());
 assert(ret_type != NULL, "sanity check: ret_type oop must not be NULL!");
 if (java_lang_Class::is_primitive(ret_type)) {
 // Only for primitive type vm allocates memory for java object.
 // See box() method.
 JvmtiExport::post_vm_object_alloc(JavaThread::current(), result);
 }
 }
 return res;
 } else {
 THROW_0(vmSymbols::java_lang_StackOverflowError());
 }
JVM_END

其中oop result = Reflection::invoke_method(method_handle(), receiver, args, CHECK_NULL)是方法的執(zhí)行過程,在\hotspot\src\share\vm\runtime路徑下找到reflection.cpp文件。

oop Reflection::invoke_method(oop method_mirror, Handle receiver, objArrayHandle args, TRAPS) {
 oop mirror = java_lang_reflect_Method::clazz(method_mirror);
 int slot = java_lang_reflect_Method::slot(method_mirror);
 bool override = java_lang_reflect_Method::override(method_mirror) != 0;
 objArrayHandle ptypes(THREAD, objArrayOop(java_lang_reflect_Method::parameter_types(method_mirror)));
 
 oop return_type_mirror = java_lang_reflect_Method::return_type(method_mirror);
 BasicType rtype;
 if (java_lang_Class::is_primitive(return_type_mirror)) {
 rtype = basic_type_mirror_to_basic_type(return_type_mirror, CHECK_NULL);
 } else {
 rtype = T_OBJECT;
 }
 
 instanceKlassHandle klass(THREAD, java_lang_Class::as_Klass(mirror));
 Method* m = klass->method_with_idnum(slot);
 if (m == NULL) {
 THROW_MSG_0(vmSymbols::java_lang_InternalError(), "invoke");
 }
 methodHandle method(THREAD, m);
 
 return invoke(klass, method, receiver, override, ptypes, rtype, args, true, THREAD);
}
 
oop Reflection::invoke(instanceKlassHandle klass, methodHandle reflected_method,
  Handle receiver, bool override, objArrayHandle ptypes,
  BasicType rtype, objArrayHandle args, bool is_method_invoke, TRAPS) {
 ResourceMark rm(THREAD);
 
 methodHandle method; // actual method to invoke
 KlassHandle target_klass; // target klass, receiver's klass for non-static
 
 // Ensure klass is initialized
 klass->initialize(CHECK_NULL);
 
 bool is_static = reflected_method->is_static();
 if (is_static) {
 // ignore receiver argument
 method = reflected_method;
 target_klass = klass;
 } else {
 // check for null receiver
 if (receiver.is_null()) {
 THROW_0(vmSymbols::java_lang_NullPointerException());
 }
 // Check class of receiver against class declaring method
 if (!receiver->is_a(klass())) {
 THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "object is not an instance of declaring class");
 }
 // target klass is receiver's klass
 target_klass = KlassHandle(THREAD, receiver->klass());
 // no need to resolve if method is private or <init>
 if (reflected_method->is_private() || reflected_method->name() == vmSymbols::object_initializer_name()) {
 method = reflected_method;
 } else {
 // resolve based on the receiver
 if (reflected_method->method_holder()->is_interface()) {
 // resolve interface call
 if (ReflectionWrapResolutionErrors) {
 // new default: 6531596
 // Match resolution errors with those thrown due to reflection inlining
 // Linktime resolution & IllegalAccessCheck already done by Class.getMethod()
 method = resolve_interface_call(klass, reflected_method, target_klass, receiver, THREAD);
 if (HAS_PENDING_EXCEPTION) {
 // Method resolution threw an exception; wrap it in an InvocationTargetException
 oop resolution_exception = PENDING_EXCEPTION;
 CLEAR_PENDING_EXCEPTION;
 JavaCallArguments args(Handle(THREAD, resolution_exception));
 THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
 vmSymbols::throwable_void_signature(),
 &args);
 }
 } else {
 method = resolve_interface_call(klass, reflected_method, target_klass, receiver, CHECK_(NULL));
 }
 } else {
 // if the method can be overridden, we resolve using the vtable index.
 assert(!reflected_method->has_itable_index(), "");
 int index = reflected_method->vtable_index();
 method = reflected_method;
 if (index != Method::nonvirtual_vtable_index) {
 // target_klass might be an arrayKlassOop but all vtables start at
 // the same place. The cast is to avoid virtual call and assertion.
 InstanceKlass* inst = (InstanceKlass*)target_klass();
 method = methodHandle(THREAD, inst->method_at_vtable(index));
 }
 if (!method.is_null()) {
 // Check for abstract methods as well
 if (method->is_abstract()) {
 // new default: 6531596
 if (ReflectionWrapResolutionErrors) {
 ResourceMark rm(THREAD);
 Handle h_origexception = Exceptions::new_exception(THREAD,
  vmSymbols::java_lang_AbstractMethodError(),
  Method::name_and_sig_as_C_string(target_klass(),
  method->name(),
  method->signature()));
 JavaCallArguments args(h_origexception);
 THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
 vmSymbols::throwable_void_signature(),
 &args);
 } else {
 ResourceMark rm(THREAD);
 THROW_MSG_0(vmSymbols::java_lang_AbstractMethodError(),
  Method::name_and_sig_as_C_string(target_klass(),
    method->name(),
    method->signature()));
 }
 }
 }
 }
 }
 }
 
 // I believe this is a ShouldNotGetHere case which requires
 // an internal vtable bug. If you ever get this please let Karen know.
 if (method.is_null()) {
 ResourceMark rm(THREAD);
 THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(),
 Method::name_and_sig_as_C_string(klass(),
    reflected_method->name(),
    reflected_method->signature()));
 }
 
 // In the JDK 1.4 reflection implementation, the security check is
 // done at the Java level
 if (!(JDK_Version::is_gte_jdk14x_version() && UseNewReflection)) {
 
 // Access checking (unless overridden by Method)
 if (!override) {
 if (!(klass->is_public() && reflected_method->is_public())) {
 bool access = Reflection::reflect_check_access(klass(), reflected_method->access_flags(), target_klass(), is_method_invoke, CHECK_NULL);
 if (!access) {
 return NULL; // exception
 }
 }
 }
 
 } // !(Universe::is_gte_jdk14x_version() && UseNewReflection)
 
 assert(ptypes->is_objArray(), "just checking");
 int args_len = args.is_null() ? 0 : args->length();
 // Check number of arguments
 if (ptypes->length() != args_len) {
 THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "wrong number of arguments");
 }
 
 // Create object to contain parameters for the JavaCall
 JavaCallArguments java_args(method->size_of_parameters());
 
 if (!is_static) {
 java_args.push_oop(receiver);
 }
 
 for (int i = 0; i < args_len; i++) {
 oop type_mirror = ptypes->obj_at(i);
 oop arg = args->obj_at(i);
 if (java_lang_Class::is_primitive(type_mirror)) {
 jvalue value;
 BasicType ptype = basic_type_mirror_to_basic_type(type_mirror, CHECK_NULL);
 BasicType atype = unbox_for_primitive(arg, &value, CHECK_NULL);
 if (ptype != atype) {
 widen(&value, atype, ptype, CHECK_NULL);
 }
 switch (ptype) {
 case T_BOOLEAN: java_args.push_int(value.z); break;
 case T_CHAR: java_args.push_int(value.c); break;
 case T_BYTE: java_args.push_int(value.b); break;
 case T_SHORT: java_args.push_int(value.s); break;
 case T_INT: java_args.push_int(value.i); break;
 case T_LONG: java_args.push_long(value.j); break;
 case T_FLOAT: java_args.push_float(value.f); break;
 case T_DOUBLE: java_args.push_double(value.d); break;
 default:
 THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch");
 }
 } else {
 if (arg != NULL) {
 Klass* k = java_lang_Class::as_Klass(type_mirror);
 if (!arg->is_a(k)) {
 THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch");
 }
 }
 Handle arg_handle(THREAD, arg); // Create handle for argument
 java_args.push_oop(arg_handle); // Push handle
 }
 }
 
 assert(java_args.size_of_parameters() == method->size_of_parameters(), "just checking");
 
 // All oops (including receiver) is passed in as Handles. An potential oop is returned as an
 // oop (i.e., NOT as an handle)
 JavaValue result(rtype);
 JavaCalls::call(&result, method, &java_args, THREAD);
 
 if (HAS_PENDING_EXCEPTION) {
 // Method threw an exception; wrap it in an InvocationTargetException
 oop target_exception = PENDING_EXCEPTION;
 CLEAR_PENDING_EXCEPTION;
 JavaCallArguments args(Handle(THREAD, target_exception));
 THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
 vmSymbols::throwable_void_signature(),
 &args);
 } else {
 if (rtype == T_BOOLEAN || rtype == T_BYTE || rtype == T_CHAR || rtype == T_SHORT)
 narrow((jvalue*) result.get_value_addr(), rtype, CHECK_NULL);
 return box((jvalue*) result.get_value_addr(), rtype, CHECK_NULL);
 }
}

Reflection::invoke_method()中調(diào)用Reflection::invoke(),然后在Reflection::invoke()方法中,當(dāng)反射調(diào)用的方法是接口方法時,調(diào)用Reflection::resolve_interface_call(),該方法依賴LinkResolver::resolve_interface_call()來完成方法的動態(tài)鏈接過程,具體實現(xiàn)就不在這里展示。

method = resolve_interface_call(klass, reflected_method, target_klass, receiver, CHECK_(NULL));
methodHandle Reflection::resolve_interface_call(instanceKlassHandle klass, methodHandle method,
      KlassHandle recv_klass, Handle receiver, TRAPS) {
 assert(!method.is_null() , "method should not be null");
 
 CallInfo info;
 Symbol* signature = method->signature();
 Symbol* name = method->name();
 LinkResolver::resolve_interface_call(info, receiver, recv_klass, klass,
     name, signature,
     KlassHandle(), false, true,
     CHECK_(methodHandle()));
 return info.selected_method();
}

如果反射調(diào)用的方法是可以被覆蓋的方法,例如Animal.print(), Reflection::invoke()最終通過查詢虛方法表vtable來確定最終的method。

 // if the method can be overridden, we resolve using the vtable index.
 assert(!reflected_method->has_itable_index(), "");
 int index = reflected_method->vtable_index();
 method = reflected_method;
 if (index != Method::nonvirtual_vtable_index) {
  // target_klass might be an arrayKlassOop but all vtables start at
  // the same place. The cast is to avoid virtual call and assertion.
  InstanceKlass* inst = (InstanceKlass*)target_klass();
  method = methodHandle(THREAD, inst->method_at_vtable(index));
 }

總結(jié)

1.method.invoke()方法支持多態(tài)特性,其native實現(xiàn)在方法真正執(zhí)行之前通過動態(tài)連接或者虛方法表來實現(xiàn)。

2.框架中使用method.invoke()執(zhí)行方法調(diào)用時,初始獲取method對象時,可以先調(diào)用一次setAccessable(true),使得后面每次調(diào)用invoke()時,節(jié)省一次方法修飾符的判斷,略微提升性能。業(yè)務(wù)允許的情況下,F(xiàn)ield同樣可以如此操作。

3.委托模式可以解決一種方案的多種實現(xiàn)之間自由切換,而代理模式只能根據(jù)傳入的被代理對象來實現(xiàn)功能。

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI