java反射之Method的invoke方法實(shí)現(xiàn)教程詳解
前言
在框架中經(jīng)常會(huì)會(huì)用到method.invoke()方法,用來(lái)執(zhí)行某個(gè)的對(duì)象的目標(biāo)方法。以前寫代碼用到反射時(shí),總是獲取先獲取Method,然后傳入對(duì)應(yīng)的Class實(shí)例對(duì)象執(zhí)行方法。然而前段時(shí)間研究invoke方法時(shí),發(fā)現(xiàn)invoke方法居然包含多態(tài)的特性,這是以前沒(méi)有考慮過(guò)的一個(gè)問(wèn)題。那么Method.invoke()方法的執(zhí)行過(guò)程是怎么實(shí)現(xiàn)的?它的多態(tài)又是如何實(shí)現(xiàn)的呢?
本文將從java和JVM的源碼實(shí)現(xiàn)深入探討invoke方法的實(shí)現(xiàn)過(guò)程。
首先給出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()方法, 然后通過(guò)反射分別獲取print()的Method對(duì)象。最后分別用Cat和Animal的實(shí)例對(duì)象去執(zhí)行print()方法。其中animalMethod.invoke(animal)和catMethod.invoke(cat),示例對(duì)象的真實(shí)類型和Method的聲明Classs是相同的,按照預(yù)期打印結(jié)果;animalMethod.invoke(cat)中,由于Cat是Animal的子類,按照多態(tài)的特性,子類調(diào)用父類的的方法,方法執(zhí)行時(shí)會(huì)動(dòng)態(tài)鏈接到子類的實(shí)現(xiàn)方法上。因此,這里會(huì)調(diào)用Cat.print()方法;而catMethod.invoke(animal)中,傳入的參數(shù)類型Animal是父類,卻期望調(diào)用子類Cat的方法,因此這一次會(huì)拋出異常。代碼打印結(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)
接下來(lái),我們來(lái)看看invoke()方法的實(shí)現(xiàn)過(guò)程。
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()方法中主要分為兩部分:訪問(wèn)控制檢查和調(diào)用MethodAccessor.invoke()實(shí)現(xiàn)方法執(zhí)行。
首先看一下訪問(wèn)控制檢查這一塊的邏輯。第一眼看到這里的邏輯的時(shí)候,很容易搞不清楚是干嘛的。通俗來(lái)講就是通過(guò)方法的修飾符(public/protected/private/package),來(lái)判斷方法的調(diào)用者是否可以訪問(wèn)該方法。這是java的基礎(chǔ)內(nèi)容,不過(guò)用代碼寫出來(lái),一下子不容易想到。訪問(wèn)控制檢查分為3步:
- 檢查override,如果override為true,跳過(guò)檢查;否則繼續(xù);
- 快速檢查,判斷該方法的修飾符modifiers是否為public,如果是跳過(guò)檢查;否則繼續(xù);
- 詳細(xì)檢查,通過(guò)方法的(protected/private/package)修飾符或方法的聲明類(例如子類可以訪問(wèn)父類的protected方法)與調(diào)用者caller之間的關(guān)系,判斷caller是否有權(quán)限訪問(wèn)該方法。
override屬性是Method的父類AccessibleObject中聲明的變量,使得程序可以控制是否跳過(guò)訪問(wèn)權(quán)限的檢查。另外,Method的實(shí)例對(duì)象中,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;
}
多說(shuō)一句,F(xiàn)ield同樣繼承了AccessibleObject,且Field的override也是初始化為false的,也就是說(shuō)并沒(méi)有按照變量的修飾符去初始化不同的值。但是我們?cè)谡{(diào)用Field.set(Object obj, Object value)時(shí),如果該Field是private修飾的,會(huì)因沒(méi)有訪問(wèn)權(quán)限而拋出異常,因此必須調(diào)用setAccessible(true)。此處非常容易理解為因?yàn)樽兞渴莗ublic的,所以override就被初始化為true。
invoke()方法中,訪問(wèn)控制檢查之后,就是通過(guò)MethodAccessor.invoke()調(diào)用方法。再來(lái)看一下代碼:
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
這里的邏輯很簡(jiǎn)單,首先將變量methodAccessor賦值給ma,在方法棧中保存一個(gè)可以直接引用的本地變量,如果methodAccessor不存在,調(diào)用acquireMethodAccessor()方法創(chuàng)建一個(gè)。
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()這三個(gè)方法,可以看到一個(gè)Method實(shí)例對(duì)象維護(hù)了一個(gè)root引用。當(dāng)調(diào)用Method.copy()進(jìn)行方法拷貝時(shí),root指向了被拷貝的對(duì)象。那么當(dāng)一個(gè)Method被多次拷貝后,調(diào)用一次setMethodAccessor()方法,就會(huì)將root引用所指向的Method的methodAccessor變量同樣賦值。例如:D -> C -> B -> A,其中X-> Y表示X = Y.copy(), 當(dāng)C對(duì)象調(diào)用setMethodAccessor()時(shí),B和A都會(huì)傳播賦值methodAccessor, 而D的methodAccessor還是null。緊接著,當(dāng)D需要獲取methodAccessor而調(diào)用acquireMethodAccessor()時(shí),D獲取root的methodAccessor, 那么D將和ABC持有相同的methodAccessor。
雖然Method中,通過(guò)維護(hù)root引用意圖使相同的方法始終保持只有一個(gè)methodAccessor實(shí)例,但是上述方法仍然無(wú)法保證相同的方法只有一個(gè)methodAccessor實(shí)例。例如通過(guò)copy()使ABCD保持關(guān)系:D -> C -> B -> A, 當(dāng)B對(duì)象調(diào)用setMethodAccessor()時(shí),B和A都會(huì)賦值methodAccessor, 而C、D的methodAccessor還是null。這時(shí)D調(diào)用acquireMethodAccessor()時(shí),D獲取root也就是C的methodAccessor,發(fā)現(xiàn)為空,然后就新創(chuàng)建了一個(gè)。從而出現(xiàn)了相同的方法中出現(xiàn)了兩個(gè)methodAccessor實(shí)例對(duì)象的現(xiàn)象。
在Class.getMethod()、Class.getDeclaredMethod()以及Class.getDeclaredMethod(String name, Class<?>... parameterTypes)方法中最終都會(huì)調(diào)用copy()方法來(lái)保障Method使用的安全性。 在比較極端加巧合的情況下,可能會(huì)引起類膨脹的問(wèn)題,這就是接下來(lái)要講到的MethodAccessor的實(shí)現(xiàn)機(jī)制。

在前面代碼中,MethodAccessor的創(chuàng)建是通過(guò)反射工廠ReflectionFactory的newMethodAccessor(Method)方法來(lái)創(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()方法檢查從配置項(xiàng)中讀取配置并設(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;
}
});
}
可以通過(guò)啟動(dòng)參數(shù)-Dsun.reflect.noInflation=false -Dsun.reflect.inflationThreshold=15來(lái)設(shè)置:

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

總體來(lái)說(shuō),當(dāng)調(diào)用invoke()時(shí),按照默認(rèn)配置,Method首先創(chuàng)建一個(gè)DelegatingMethodAccessorImpl對(duì)象,并設(shè)置一個(gè)被委托的NativeMethodAccessorImpl對(duì)象,那么method.invoke()就被轉(zhuǎn)換成DelegatingMethodAccessorImpl.invoke(),然后又被委托給NativeMethodAccessorImp.invoke()實(shí)現(xiàn)。當(dāng)NativeMethodAccessorImp.invoke()調(diào)用次數(shù)超過(guò)一定熱度時(shí)(默認(rèn)15次),被委托方又被轉(zhuǎn)換成代理類來(lái)實(shí)現(xiàn)。
之前提到過(guò)在極端情況下,同一個(gè)方法的Method對(duì)象存在多個(gè)不同拷貝拷貝時(shí),可能存在多個(gè)MethodAccessor對(duì)象。那么當(dāng)多次調(diào)用后,必然會(huì)生成兩個(gè)重復(fù)功能的代理類。當(dāng)然,一般情況下,生成兩個(gè)代理類并沒(méi)有較大的影響。
其中代理類的具體字節(jié)碼實(shí)現(xiàn)過(guò)程較為復(fù)雜,大體思想是生成一個(gè)如下所示的類:
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()實(shí)現(xiàn)是在jdk中的完成的。接下來(lái)我們將目光移到NativeMethodAccessorImp的native方法invoke0();
首先,在\jdk\src\share\native\sun\reflect路徑下找到NativeAccessors.c, 其中有Java_sun_reflect_NativeMethodAccessorImpl _invoke0()方法,根據(jù)JNI定義函數(shù)名的規(guī)則"包名_類名_方法名",這就是我們要找的native方法實(shí)現(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_開(kāi)頭的函數(shù)定義在jvm.cpp文件中,不熟悉的話可以通過(guò)頭文件jvm.h看出來(lái)。繼續(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í)行過(guò)程,在\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)用的方法是接口方法時(shí),調(diào)用Reflection::resolve_interface_call(),該方法依賴LinkResolver::resolve_interface_call()來(lái)完成方法的動(dòng)態(tài)鏈接過(guò)程,具體實(shí)現(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()最終通過(guò)查詢虛方法表vtable來(lái)確定最終的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實(shí)現(xiàn)在方法真正執(zhí)行之前通過(guò)動(dòng)態(tài)連接或者虛方法表來(lái)實(shí)現(xiàn)。
2.框架中使用method.invoke()執(zhí)行方法調(diào)用時(shí),初始獲取method對(duì)象時(shí),可以先調(diào)用一次setAccessable(true),使得后面每次調(diào)用invoke()時(shí),節(jié)省一次方法修飾符的判斷,略微提升性能。業(yè)務(wù)允許的情況下,F(xiàn)ield同樣可以如此操作。
3.委托模式可以解決一種方案的多種實(shí)現(xiàn)之間自由切換,而代理模式只能根據(jù)傳入的被代理對(duì)象來(lái)實(shí)現(xiàn)功能。
到此這篇關(guān)于java反射之Method的invoke方法實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)java反射Method的invoke方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
參考文章:
相關(guān)文章
springboot整合mybatis分頁(yè)攔截器的問(wèn)題小結(jié)
springboot整合mybatis分頁(yè)攔截器,分頁(yè)攔截實(shí)際上就是獲取sql后將sql拼接limit,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-07-07
探索Java中的equals()和hashCode()方法_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了探索Java中的equals()和hashCode()方法的相關(guān)資料,需要的朋友可以參考下2017-05-05
Java實(shí)現(xiàn)快速排序算法(Quicktsort)
這篇文章主要介紹了Java實(shí)現(xiàn)快速排序算法(Quicktsort),有需要的朋友可以參考一下2013-12-12
Java中的SynchronousQueue阻塞隊(duì)列及使用場(chǎng)景解析
這篇文章主要介紹了Java中的SynchronousQueue阻塞隊(duì)列及使用場(chǎng)景解析,SynchronousQueue 是 Java 中的一個(gè)特殊的阻塞隊(duì)列,它的主要特點(diǎn)是它的容量為0,這意味著 SynchronousQueue不會(huì)存儲(chǔ)任何元素,需要的朋友可以參考下2023-12-12
Java多線程并發(fā)synchronized?關(guān)鍵字
這篇文章主要介紹了Java多線程并發(fā)synchronized?關(guān)鍵字,Java?在虛擬機(jī)層面提供了?synchronized?關(guān)鍵字供開(kāi)發(fā)者快速實(shí)現(xiàn)互斥同步的重量級(jí)鎖來(lái)保障線程安全。2022-06-06
如何基于java實(shí)現(xiàn)Gauss消元法過(guò)程解析
這篇文章主要介紹了如何基于java實(shí)現(xiàn)Gauss消元法過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
JAVA對(duì)字符串進(jìn)行32位MD5加密的實(shí)踐
本文主要介紹了JAVA對(duì)字符串進(jìn)行32位MD5加密的實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
SpringBoot 整合 Lettuce Redis的實(shí)現(xiàn)方法
這篇文章主要介紹了SpringBoot 整合 Lettuce Redis的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07

