在NDK中,我們通過env->GetStaticMethodID來查找一個靜態方法,那返回值jmethodID到底是什麼了? 接下來,來看一下GetStaticMethodID內部邏輯。
env->GetStaticMethodID
實際會調用jni_internal.cc#GetStaticMethodID
來看 art/runtime/jni_internal.cc
可以看到最終調用了FindMethodID,主要步驟,已通過代碼註釋標記。
static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class,
const char* name, const char* sig, bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(jni_class)); //確認是否已經初始化完畢
if (c == nullptr) {
return nullptr;
}
mirror::ArtMethod* method = nullptr;
if (is_static) { //是否是靜態函數
method = c->FindDirectMethod(name, sig);
} else if (c->IsInterface()) { //是否是接口函數
method = c->FindInterfaceMethod(name, sig); //--> 實際調用的也是FindVirtualMethod
} else { //是否是虛函數
method = c->FindVirtualMethod(name, sig);
if (method == nullptr) {
// No virtual method matching the signature. Search declared
// private methods and constructors.
method = c->FindDeclaredDirectMethod(name, sig);
}
}
if (method == nullptr || method->IsStatic() != is_static) {
// >>>>>>>> 如果method爲null或不爲static,拋出NoSuchMethodError,這個開發時候經常會遇到
ThrowNoSuchMethodError(soa, c, name, sig, is_static ? "static" : "non-static");
return nullptr;
}
return soa.EncodeMethod(method); //將ArtMethod進行編碼,返回一個jmethodID
}
可以看到,會判斷是否是靜態函數,如果是靜態函數,就調用FindDirectMethod
,否則無論是接口函數還是虛函數,都是調用的FindVirtualMethod
。這兩個方法具體內部邏輯我們先略過,從返回值可以知道,這兩個方法都會找到ArtMethod。
再來看art/runtime/scoped_thread_state_change.h#EncodeMethod()
jmethodID EncodeMethod(mirror::ArtMethod* method) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Locks::mutator_lock_->AssertSharedHeld(Self());
DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states.
CHECK(!kMovingMethods);
return reinterpret_cast<jmethodID>(method); //將ArtMethod強轉爲jmethodId,即ArtMethod就是jmethodId
}
這裏將找到的ArtMethod強轉爲jmethodID,即ArtMethod就是jmethodID,並最終返回。
小結
我們可以得出結論: ArtMethod就是jmethodID
ArtMethod位於art/runtime/mirror/art_method.cc,是一個結構體,ArtMethod中保存着方法的 類、訪問權限和執行地址等信息。
其他
源碼爲Android 5.1.0_r3