java反射之Method的invoke方法實現(xiàn)教程詳解
前言
在框架中經(jīng)常會會用到method.invoke()方法,用來執(zhí)行某個的對象的目標方法。以前寫代碼用到反射時,總是獲取先獲取Method,然后傳入對應的Class實例對象執(zhí)行方法。然而前段時間研究invoke方法時,發(fā)現(xiàn)invoke方法居然包含多態(tài)的特性,這是以前沒有考慮過的一個問題。那么Method.invoke()方法的執(zhí)行過程是怎么實現(xiàn)的?它的多態(tài)又是如何實現(xiàn)的呢?
本文將從java和JVM的源碼實現(xiàn)深入探討invoke方法的實現(xiàn)過程。
首先給出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是相同的,按照預期打印結(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步:
- 檢查override,如果override為true,跳過檢查;否則繼續(xù);
- 快速檢查,判斷該方法的修飾符modifiers是否為public,如果是跳過檢查;否則繼續(xù);
- 詳細檢查,通過方法的(protected/private/package)修飾符或方法的聲明類(例如子類可以訪問父類的protected方法)與調(diào)用者caller之間的關(guān)系,判斷caller是否有權(quán)限訪問該方法。
override屬性是Method的父類AccessibleObject中聲明的變量,使得程序可以控制是否跳過訪問權(quán)限的檢查。另外,Method的實例對象中,override屬性的初始值設置為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引用。當調(diào)用Method.copy()進行方法拷貝時,root指向了被拷貝的對象。那么當一個Method被多次拷貝后,調(diào)用一次setMethodAccessor()方法,就會將root引用所指向的Method的methodAccessor變量同樣賦值。例如:D -> C -> B -> A,其中X-> Y表示X = Y.copy(), 當C對象調(diào)用setMethodAccessor()時,B和A都會傳播賦值methodAccessor, 而D的methodAccessor還是null。緊接著,當D需要獲取methodAccessor而調(diào)用acquireMethodAccessor()時,D獲取root的methodAccessor, 那么D將和ABC持有相同的methodAccessor。
雖然Method中,通過維護root引用意圖使相同的方法始終保持只有一個methodAccessor實例,但是上述方法仍然無法保證相同的方法只有一個methodAccessor實例。例如通過copy()使ABCD保持關(guān)系:D -> C -> B -> A, 當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)機制。

在前面代碼中,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()方法檢查從配置項中讀取配置并設置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來設置:

結(jié)合字面意思及下面代碼理解,這兩個配置sun.reflect.noInflation是控制是否立即進行類膨脹,sun.reflect.inflationThreshold是設置類膨脹閾值。
創(chuàng)建MethodAccessor有兩種選擇,一種是當sun.reflect.noInflation配置項為true時,ReflectionFactory利用MethodAccessor的字節(jié)碼生成類 MethodAccessorGenerator直接創(chuàng)建一個代理類,通過間接調(diào)用原方法完成invoke()任務,具體實現(xiàn)稍后給出。MethodAccessor的另一種實現(xiàn)方式是,創(chuàng)建DelegatingMethodAccessorImpl 委托類,并將執(zhí)行invoke()方法的具體內(nèi)容交由NativeMethodAccessorImpl實現(xiàn),而NativeMethodAccessorImpl最終調(diào)用native方法完成invoke()任務。以下是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);
可以看到,當numInvocations數(shù)量大于配置項sun.reflect.inflationThreshold即類膨脹閾值時, 使用MethodAccessorGenerator創(chuàng)建一個代理類對象,并且將被委托的NativeMethodAccessorImpl的parent,也就是委托類DelegatingMethodAccessorImpl的委托類設置為這個生成的代理對象。這么說可能有點繞,下面用一幅圖表示這個過程。

總體來說,當調(diào)用invoke()時,按照默認配置,Method首先創(chuàng)建一個DelegatingMethodAccessorImpl對象,并設置一個被委托的NativeMethodAccessorImpl對象,那么method.invoke()就被轉(zhuǎn)換成DelegatingMethodAccessorImpl.invoke(),然后又被委托給NativeMethodAccessorImp.invoke()實現(xiàn)。當NativeMethodAccessorImp.invoke()調(diào)用次數(shù)超過一定熱度時(默認15次),被委托方又被轉(zhuǎn)換成代理類來實現(xiàn)。
之前提到過在極端情況下,同一個方法的Method對象存在多個不同拷貝拷貝時,可能存在多個MethodAccessor對象。那么當多次調(diào)用后,必然會生成兩個重復功能的代理類。當然,一般情況下,生成兩個代理類并沒有較大的影響。
其中代理類的具體字節(jié)碼實現(xiàn)過程較為復雜,大體思想是生成一個如下所示的類:
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();
首先,在\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()方法中,當反射調(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è)務允許的情況下,F(xiàn)ield同樣可以如此操作。
3.委托模式可以解決一種方案的多種實現(xiàn)之間自由切換,而代理模式只能根據(jù)傳入的被代理對象來實現(xiàn)功能。
到此這篇關(guān)于java反射之Method的invoke方法實現(xiàn)的文章就介紹到這了,更多相關(guān)java反射Method的invoke方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
參考文章:
相關(guān)文章
springboot整合mybatis分頁攔截器的問題小結(jié)
springboot整合mybatis分頁攔截器,分頁攔截實際上就是獲取sql后將sql拼接limit,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-07-07
探索Java中的equals()和hashCode()方法_動力節(jié)點Java學院整理
這篇文章主要介紹了探索Java中的equals()和hashCode()方法的相關(guān)資料,需要的朋友可以參考下2017-05-05
Java實現(xiàn)快速排序算法(Quicktsort)
這篇文章主要介紹了Java實現(xiàn)快速排序算法(Quicktsort),有需要的朋友可以參考一下2013-12-12
Java中的SynchronousQueue阻塞隊列及使用場景解析
這篇文章主要介紹了Java中的SynchronousQueue阻塞隊列及使用場景解析,SynchronousQueue 是 Java 中的一個特殊的阻塞隊列,它的主要特點是它的容量為0,這意味著 SynchronousQueue不會存儲任何元素,需要的朋友可以參考下2023-12-12
Java多線程并發(fā)synchronized?關(guān)鍵字
這篇文章主要介紹了Java多線程并發(fā)synchronized?關(guān)鍵字,Java?在虛擬機層面提供了?synchronized?關(guān)鍵字供開發(fā)者快速實現(xiàn)互斥同步的重量級鎖來保障線程安全。2022-06-06
SpringBoot 整合 Lettuce Redis的實現(xiàn)方法
這篇文章主要介紹了SpringBoot 整合 Lettuce Redis的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-07-07

