久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁技術文章
文章詳情頁

java反射之Method的invoke方法實現教程詳解

瀏覽:63日期:2022-08-18 15:50:41

前言

在框架中經常會會用到method.invoke()方法,用來執行某個的對象的目標方法。以前寫代碼用到反射時,總是獲取先獲取Method,然后傳入對應的Class實例對象執行方法。然而前段時間研究invoke方法時,發現invoke方法居然包含多態的特性,這是以前沒有考慮過的一個問題。那么Method.invoke()方法的執行過程是怎么實現的?它的多態又是如何實現的呢?

本文將從java和JVM的源碼實現深入探討invoke方法的實現過程。

首先給出invoke方法多態特性的演示代碼:

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 {@Overridepublic void print() {System.out.println('Cat.print()');}}

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

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()方法的實現過程。

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()方法中主要分為兩部分:訪問控制檢查和調用MethodAccessor.invoke()實現方法執行。

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

檢查override,如果override為true,跳過檢查;否則繼續; 快速檢查,判斷該方法的修飾符modifiers是否為public,如果是跳過檢查;否則繼續; 詳細檢查,通過方法的(protected/private/package)修飾符或方法的聲明類(例如子類可以訪問父類的protected方法)與調用者caller之間的關系,判斷caller是否有權限訪問該方法。

override屬性是Method的父類AccessibleObject中聲明的變量,使得程序可以控制是否跳過訪問權限的檢查。另外,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; }

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

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

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

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

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引用。當調用Method.copy()進行方法拷貝時,root指向了被拷貝的對象。那么當一個Method被多次拷貝后,調用一次setMethodAccessor()方法,就會將root引用所指向的Method的methodAccessor變量同樣賦值。例如:D -> C -> B -> A,其中X-> Y表示X = Y.copy(), 當C對象調用setMethodAccessor()時,B和A都會傳播賦值methodAccessor, 而D的methodAccessor還是null。緊接著,當D需要獲取methodAccessor而調用acquireMethodAccessor()時,D獲取root的methodAccessor, 那么D將和ABC持有相同的methodAccessor。

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

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

java反射之Method的invoke方法實現教程詳解

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

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; } }); }

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

java反射之Method的invoke方法實現教程詳解

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

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

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數量大于配置項sun.reflect.inflationThreshold即類膨脹閾值時, 使用MethodAccessorGenerator創建一個代理類對象,并且將被委托的NativeMethodAccessorImpl的parent,也就是委托類DelegatingMethodAccessorImpl的委托類設置為這個生成的代理對象。這么說可能有點繞,下面用一幅圖表示這個過程。

java反射之Method的invoke方法實現教程詳解

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

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

其中代理類的具體字節碼實現過程較為復雜,大體思想是生成一個如下所示的類:

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 類中,方法的執行有多態的特性,而NativeMethodAccessorImp的invoke()實現是在jdk中的完成的。接下來我們將目光移到NativeMethodAccessorImp的native方法invoke0();

openJDK下載地址

首先,在jdksrcsharenativesunreflect路徑下找到NativeAccessors.c, 其中有Java_sun_reflect_NativeMethodAccessorImpl _invoke0()方法,根據JNI定義函數名的規則'包名_類名_方法名',這就是我們要找的native方法實現入口。

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);}

方法調用JVM_InvokeMethod(), 一般以JVM_開頭的函數定義在jvm.cpp文件中,不熟悉的話可以通過頭文件jvm.h看出來。繼續追蹤,發現jvm.cpp文件位于spotsrcsharevmprims文件夾下。

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)是方法的執行過程,在hotspotsrcsharevmruntime路徑下找到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()中調用Reflection::invoke(),然后在Reflection::invoke()方法中,當反射調用的方法是接口方法時,調用Reflection::resolve_interface_call(),該方法依賴LinkResolver::resolve_interface_call()來完成方法的動態鏈接過程,具體實現就不在這里展示。

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();}

如果反射調用的方法是可以被覆蓋的方法,例如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)); }

總結

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

2.框架中使用method.invoke()執行方法調用時,初始獲取method對象時,可以先調用一次setAccessable(true),使得后面每次調用invoke()時,節省一次方法修飾符的判斷,略微提升性能。業務允許的情況下,Field同樣可以如此操作。

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

到此這篇關于java反射之Method的invoke方法實現的文章就介紹到這了,更多相關java反射Method的invoke方法內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

參考文章:

JAVA深入研究——Method的Invoke方法。

標簽: Java
相關文章:
主站蜘蛛池模板: av网址在线播放 | 91精品久久久久久久久久入口 | 国产成人高清精品免费5388 | 久久久精品免费观看 | 亚洲精品自拍视频 | 久久精品国产免费 | 免费观看的av | 国产美女一区二区 | 黑人xxx视频 | 91一区二区三区 | 久久国产精品99国产 | 视频网站免费观看 | 国产精品96久久久久久久 | 欧美三级在线 | 欧美日韩在线观看一区二区三区 | 久久99深爱久久99精品 | 国产精品178页 | 成人av免费在线观看 | 碰在线视频 | 日韩精品一区二区三区在线观看 | 欧美日韩一区二区电影 | 亚洲精品一区二区三区在线 | 国产精品久久久久久久娇妻 | 女人久久久久久久 | 香蕉在线影院 | 在线观看中文字幕亚洲 | 狠狠久久综合 | 精品一二三四区 | 亚洲高清免费视频 | 91电影在线 | 一区二区中文字幕 | 久久精品成人 | 男女羞羞视频免费在线观看 | 精品国产乱码久久久久久1区2区 | 91中文在线 | 999国内精品永久免费视频 | www.国产精品 | 成人免费xxxxx在线视频软件 | 免看一级一片 | 91精品国产综合久久久久久蜜臀 | 欧美精品一区二区三区免费视频 | 日韩成人精品在线 | 99久久精品免费看国产免费软件 | 超碰人人插 | www国产xxx| 成人欧美一区二区三区白人 | 毛片免费视频 | 精品久久久久久国产三级 | 日韩一级二级三级 | 日韩国产精品一区二区 | 精品一区二区三区久久 | 天天干狠狠干 | 特a级片 | 99精品欧美一区二区三区综合在线 | 日韩素人一区二区三区 | 欧美一区二区三区在线视频 | 免费成人av网站 | 免费毛片网 | 婷婷在线观看视频 | 天天干干| 午夜精品久久久 | 国产在线欧美 | 亚洲国产精品一区 | 中文av网站 | 免费99视频| 国产片侵犯亲女视频播放 | 日本久久久一区二区三区 | 青青99 | 亚洲一区二区三区免费观看 | 国产精品69久久久久水密桃 | 日本一区二区电影 | av网站网址| 国产日本欧美在线 | 国产拍拍拍拍拍拍拍拍拍拍拍拍拍 | 91亚色 | 亚洲乱码国产乱码精品精98午夜 | 一区二区免费视频 | 亚洲美女在线视频 | 中文字幕av亚洲精品一部二部 | 日韩视频网站在线观看 | ririsao久久精品一区 | 久久综合久久综合久久综合 | 久久精品一区二区三区四区毛片 | 一区二区国产在线观看 | 国产女人高潮视频在线观看 | 免费看片色| 国产精品一区2区 | 久久精品亚洲精品 | 在线观看免费av电影 | 91 在线观看 | 四虎视频 | 日本久久精品视频 | 亚洲成人日韩 | 国产伦精品一区二区三区在线 | 啪一啪| 在线视频91 | 久久九九视频 | 免费三片在线观看网站 | 成人日批 | 欧美性猛交一区二区三区精品 | 日韩国产欧美视频 | 欧美精品在线一区二区三区 | 久章操| 欧美日韩在线播放 | 日韩毛片免费看 | 成人在线高清视频 | 国产欧美网址 | 欧美 日韩 国产 一区 | 欧美一区久久 | 1204国产成人精品视频 | 久草院线| 日本在线黄色 | 亚洲超碰av| 久久天堂av综合合色蜜桃网 | 婷婷在线免费视频 | 国产一区二区在线看 | 黄色影片网址 | 亚洲精品久久久久午夜 | 国产欧美日韩 | 精品av| 资源av| 超级碰在线视频 | 欧美一级网站 | 国产精品国色综合久久 | 精品国产91乱码一区二区三区 | 日本在线免费观看 | 国产91精品在线 | 精品在线一区二区三区 | 欧美成年黄网站色视频 | 琪琪午夜伦伦电影福利片 | 欧美aaaaa| 午夜影院免费视频 | 美女久久| 二区国产 | 久久国产成人 | 国产精品久久久久久二区 | 日韩国产 | 国产成人久久 | 黄色影片网址 | 日本一级中文字幕久久久久久 | 黄免费视频 | 免费一级毛片 | 亚洲欧美日韩在线一区 | 国产中文字幕一区 | 亚洲精品国精品久久99热 | 99精品欧美一区二区三区 | 亚洲成av人片在线观看无码 | 中文字幕在线免费 | 亚洲不卡网站 | 国产一区二区视频免费 | 欧美一区二区三区在线观看 | 亚洲欧美激情精品一区二区 | 在线免费视频一区二区 | 97久久久国产精品 | 日韩三级在线 | 青娱乐国产精品视频 | 亚洲精品一区二区三区在线播放 | 欧美一区二区三区在线看 | 久热免费在线观看 | 四虎永久网址 | 伦理一区| 看全黄大色黄大片老人做 | 在线观看理论电影 | a免费观看 | 久久99精品久久久噜噜最新章节 | 黄色毛片视频网站 | 天天狠狠操 | 中文字幕二区 | 日本免费视频 | 亚州综合一区 | 天堂一区 | 在线看免费的a | 日韩成人av在线 | 国产伦精品久久久一区二区三区 | 欧美午夜寂寞影院 | 在线看免费黄色片 | 国产在线观看二区 | 一二区视频| 97伦理电影| www.99热这里只有精品 | 欧美精品在线一区 | 国产一级毛片在线视频 | 精品久久久久久亚洲精品 | 九色视频在线播放 | 亚洲污视频 | 狠狠色狠狠色综合网 | 男人的天堂亚洲 | 在线一区二区三区做爰视频网站 | 国产一级片| av一区二区三区四区 | 久久亚洲天堂 | 亚洲国产精品99久久久久久久久 | 黄色一级在线观看 | 最新日韩av网址 | 日韩av一区二区三区四区 | av影片在线播放 | 四虎影院入口 | 日韩av在线一区 | 美女一区二区三区四区 | 日韩成人影院 | 亚洲精品视频一区 | 久久99国产精品 | 在线看亚洲 | 日韩精品视频在线观看免费 | 国产乱码精品一区二区三区av | 丁香五月亚洲综合在线 | 亚洲中午字幕 | 成人综合在线观看 | 综合一区二区三区 | 黄色毛片观看 | 久久久国产一区 | 欧美不卡视频 | 电影91久久久 | 538在线精品| 国产成人精品一区二区三区视频 | 久久综合狠狠综合久久综合88 | 成人一区二区三区久久精品嫩草 | 91久久精品一区二区二区 | 国产免费视频 | 亚洲色图偷拍视频 | 欧美精品在线不卡 | 国产成人精品久久 | 日韩免费一级 | 日韩一级黄色大片 | 久久久久久久国产精品 | 国产午夜精品久久久久久久 | av免费观看网站 | 懂色av色香蕉一区二区蜜桃 | 国产乱淫av片 | 97视频久久 | 婷婷激情综合 | 久久久久久久 | 久久精品影片 | 免费观看国产视频在线 | 国产毛片毛片 | 中文字幕一区在线观看视频 | 精品日韩一区二区 | 99色综合| 欧美一级片在线观看 | 成人黄色片网站 | 曰批视频在线观看 | 久久久久久精 | 欧美一级全黄 | 欧美黄色一区 | 日韩精品1区 | 亚洲a网 | 狠狠综合久久av一区二区小说 | 国产精品视频一区二区三区 | 激情网站免费观看 | 一级毛片在线 | 国产福利精品一区 | 欧洲精品久久久 | 99精品免费 | 中文在线观看www | 四虎视频 | 亚洲色图在线播放 | 国产在线色 | 日韩xxxbbb | 91在线精品秘密一区二区 | 另类sb东北妇女av | 国产精品久久久久久中文字 | 九九热欧美 | 羞羞视频网站在线看 | 精品久久香蕉国产线看观看亚洲 | 呦呦在线观看 | 伊人青青草 | 国产永久免费 | 刘亦菲的毛片 | 97色综合 | 亚洲综合色视频在线观看 | 免费观看视频毛片 | 在线视频久久 | 一级片在线观看 | 国产福利精品一区 | 久久久久久一区 | а天堂中文最新一区二区三区 | 亚洲欧洲视频 | 91久久精品久久国产性色也91 | 色婷网 | 蜜桃视频一区二区三区 | 久久国产99 | av色伊人久久综合一区二区 | 欧美专区在线 | 成人a在线观看 | 国产一区二区三区免费观看 | 天天操操 | 狠狠爱亚洲 | 龙珠z国语291集普通话 | 亚州精品成人 | 免费在线观看国产 | 国产一区二区精品在线观看 | 精品护士一区二区三区 | 欧美日韩在线第一页 | 久久久久久一区 | aa毛片| 精品在线不卡 | 国产无区一区二区三麻豆 | 天天碰天天操 | 亚洲精品成人av | h片在线免费观看 | 午夜窝窝 | 亚洲视频免费观看 | 欧美日韩综合视频 | 国产欧美精品一区二区三区四区 | 日韩在线免费视频 | 欧美午夜一区二区三区免费大片 | 91视频免费播放 | 欧美激情一区二区 | 毛片激情永久免费 | 成人av一区二区三区 | 久草成人| 女人色网 | 69性欧美高清影院 | 亚洲视频三区 | 久久久久9999国产精品 | 欧美综合国产精品久久丁香 | 日韩a视频 | 欧美视频一区二区三区在线观看 | 成人免费视频视频在线观看 免费 | 日韩视频在线观看 | 国产福利精品一区 | 青青久久 | 一级黄色片在线 | 国产精品jizz在线观看麻豆 | 国产成人在线免费观看 | 国产精品自拍一区 | 一区二区亚洲 | 男女视频在线免费观看 | 亚洲区在线 | 91精品视频在线播放 | 亚洲无吗电影 | 超碰在线一区二区三区 | 91亚洲精品一区 | 欧美一区久久 | 九九热九九 | 日韩精品| 日韩欧美三区 | 欧洲成人在线观看 | 国产亚洲精品精品国产亚洲综合 | 女朋友的闺蜜3韩国三级 | 久久综合久久综合久久综合 | 久久生活片 | 中文av网站 | 四虎免看黄 | 精产国产伦理一二三区 | 中国一级特黄毛片大片 | 九九九色 | 综合色播| 国产精品美女视频一区二区三区 | 狠狠操中文字幕 | 九九热热九九 | 激情视频网站 | 99精品热 | 欧美在线影院 | 伊人福利视频 | 91精品在线观看入口 | 91.com在线观看 | 91精品国产自产91精品 | 精品天堂 | 亚洲欧美成人影院 | 涩涩视频在线看 | 日韩一二三 | 91资源在线 | 欧美黄色一区 | www.亚洲一区二区 | 中文字幕精品一区二区三区精品 | 手机久久看片 | 九九亚洲 | 欧美第一页 | 91tv亚洲精品香蕉国产一区 | 大香伊蕉在人线视频777 | 日韩视频中文 | 在线亚洲精品 | 午夜视频精品 | 视频二区在线观看 | 婷婷色av| 精品一区二区三区免费视频 | 91精品国产91久久久久久吃药 | 亚洲麻豆精品 | 国产免费av在线 | 国产精品激情在线观看 | 中文字幕在线观看网站 | 中字幕视频在线永久在线观看免费 | 国产一区二区精品在线观看 | 亚洲国产精品自拍 | 亚洲欧美日韩精品 | 欧美一区不卡 | 国产欧美精品一区二区色综合朱莉 | 中文在线视频 | 精品 99| 精品欧美一区二区三区久久久 | 欧美日韩精品一区二区 | 久在线视频 | 91九色porny首页最多播放 | 99热精品国产 | 韩日精品视频 | 一区二区三区中文字幕 | 超碰最新网址 | 台湾佬亚洲色图 | 国产福利在线观看 | 色悠久久久 | 亚洲免费人成在线视频观看 | a国产视频 | 亚洲欧美少妇 | 久久人人爽人人爽人人片av高清 | 成年人在线观看 | 人人人人人你人人人人人 | 国产日韩精品在线观看 | 亚洲 欧美 另类 综合 偷拍 | 蕉伊人| 中文精品久久久 | 最新黄色网址在线播放 | 成人欧美 | 久久成人在线视频 | av官网 | 国产精品免费观看 | 狠狠操天天操 | 精品在线播放 | 欧洲精品视频在线观看 | 天天草天天| 午夜国产精品视频 | 久久久噜噜噜www成人网 | 精品一区二区三区在线观看 | 大香伊蕉在人线视频777 | 国产人成精品一区二区三 | 亚洲一区二区 | 成人在线不卡 | 日本三级在线观看中文字 | 亚洲精品一区二区三区在线 | 91免费观看视频 | 成人影院在线 | 美女视频久久 | 亚洲 欧美 自拍偷拍 | 久久女人 | 亚洲欧美综合 | 一区二区影院 | 中文字幕自拍偷拍 | 亚洲成人伦理 | 成年人精品视频 | 天天天操操操 | 亚洲美女av在线 | 国产欧美专区 | av网站在线播放 | 二区三区 | 久久久久久精 | 亚洲精品久久久久久久久久久久久 | 久久成人国产 | 欧美中文字幕在线观看 | 日本在线网 | 一二三区字幕免费观看av | 91久久精品一区二区别 | 精品久久久久久久久福利 | 国产精品一区二 | 亚洲人久久| 视频一二区 | 色橹橹欧美在线观看视频高清 | 蜜桃免费视频 | 久久久精品一区 | 91精品国产综合久久精品 | 久久久久久久久久久亚洲 | 天天干天天操 | 亚洲青涩在线 | 日韩精品日韩激情日韩综合 | 久草最新| 亚洲精品国产第一综合99久久 | 欧美精品久久久 | 成人免费在线视频观看 | 欧美成人精品一区二区男人看 | 亚洲第一色片 | 国产精品一区2区 | 少妇精品视频在线观看 | 成人av小说 | 欧美一级内谢 | 综合一区二区三区 | 欧美成人免费视频 | 精品国产91久久久久久久 | 国产精品久久久久久久午夜片 | 久草网在线视频 | 日韩精品一区二区在线观看视频 | 天天综合网网欲色 | 精品国产一区一区二区三亚瑟 | 特黄特黄aaaa级毛片免费看 | 国产一级一级国产 | 久久久久无码国产精品一区 | 美女午夜影院 | 成人免费视频观看视频 | 成人在线看片 | 婷婷激情五月 | 国产女爽爽视频精品免费 | 国产午夜视频 | 精品一级 | 午夜免费福利视频 | 久久精品一二三四 | 天天看天天操 | 国产精品一区二区三 | av免费网站在线观看 | 久草久草久草 | 国产一区中文字幕 | 日韩中文在线观看 | 羞羞视频免费网站 | 一级黄色片aaa | 久久精品亚洲欧美日韩精品中文字幕 | 精品国产欧美一区二区 | 天天爽夜夜爽夜夜爽精品视频 | 午夜天堂精品久久久久 | 亚洲 欧美 日韩在线 | 免费日韩| 日韩不卡一区二区 | 国产成人啪精品午夜在线观看 | 亚洲国产成人精品女人久久久 | 国产在线国产 | 君岛美绪一区二区三区在线视频 | 欧美久久久久久久久久久久久久 | 国产精品久久久久久久一区探花 | 欧美日韩三级 | 中文字幕三区 | 欧美精品一区在线发布 | 日韩精品在线网站 | 国产精品久久久久久久久免费 | 国产成人精品一区二区在线 | 男女视频网站 | 91精品欧美久久久久久久 | 欧美日韩高清在线一区 | 亚洲国产精品99久久久久久久久 | 网站一区二区三区 | 日韩在线观看一区 | 国产精品久久精品 | 亚洲精品乱码久久久久久9色 | 欧美黄色激情 | av在线官网 | 国产午夜精品视频 | 免费黄色大片 | 国产精品一区二 | 婷婷毛片| 一级篇| 超碰人人爱 | 午夜国产视频 | 精品久久久久久久久久久久久久久久久久久 | 青青草久久网 | 爱色av| 久久都是精品 | 中文字幕毛片 | 人人射 | 欧美日韩在线免费 | 免费一区| 中文字幕视频在线观看 | 日韩欧美国产精品综合嫩v 亚洲欧美日韩在线 | 久久国产精品免费一区二区三区 | www.日韩.com| 亚洲永久免费观看 | 亚洲欧美日韩国产综合精品二区 | 另类亚洲专区 | 国产传媒一区 | 亚洲人人| 亚洲一区二区三区在线播放 | 狠狠人人 | 国产精品18hdxxxⅹ在线 | 精品久 | 日韩成人高清电影 | 精品一区二区三区在线观看 | 欧美不卡视频 | 真人一级毛片 | 99国产精品99久久久久久 | 一道本一区二区三区 | 欧美在线a | 伊人网网站 | 国产精品一区二 | 在线色网 | 激情欧美一区二区三区中文字幕 | 天堂国产| 欧美日韩视频 | 偷派自拍 | 在线a视频 | 欧美视频免费在线观看 | 黄色91| 成人av网页 | 国产wwwcom| 日韩不卡一区 | 精品在线一区二区三区 | 青青草精品 | 33eee在线视频免费观看 | 久久精品一区 | 日韩在线观看一区 | 午夜精品视频在线观看 | 国产一区二区三区免费视频 | 久久亚洲国产视频 | 中文字幕 亚洲一区 | 爱爱视频网站 | 91精品国产欧美一区二区成人 | 亚洲tv国产 | 在线视频一区二区三区 | 欧美色成人 | 免费av片网站 | 日韩在线一区二区三区 | 久久伊人青青草 | 91国自产精品中文字幕亚洲 | 亚洲欧美日韩精品久久奇米色影视 | 羞羞视频在线观免费观看 | 精品一区二区视频 | 欧美电影一区 | 国产视频一二区 | 在线干 | 亚洲每日更新 | 中国大陆高清aⅴ毛片 | 中文字幕一区二区三区精彩视频 | 国产精品久久国产愉拍 | 国产中文字幕一区 | 国产精品一区二区在线看 | 国产精品一区二区av | 国产1区2区 | 精品一区久久 | 91看片在线观看 | 日韩www| 亚洲天堂一区二区 | 亚洲无吗视频 |