1. 程式人生 > >JNI原生方法命名規則

JNI原生方法命名規則

JNI呼叫函式命名規則

一、引用

    Resolving Native Method Names

    Dynamic linkers resolve entries based on their names. A native method name is concatenated from the following components:

  • the prefix Java_
  • a mangled fully-qualified class name
  • an underscore (“_”) separator
  • a mangled method name
  • for overloaded native methods, two underscores (“__”) followed by the mangled argument signature

    The VM checks for a method name match for methods that reside in the native library. The VM looks first for the short name; that is, the name without the argument signature. It then looks for the long name, which is the name with the argument signature. Programmers need to use the long name only when a native method is overloaded with another native method. However, this is not a problem if the native method has the same name as a nonnative method. A nonnative method (a Java method) does not reside in the native library.

    In the following example, the native method g does not have to be linked using the long name because the other method g is not a native method, and thus is not in the native library.

class Cls1 {

  int g(int i);

  native int g(double d);

}

    We adopted a simple name-mangling scheme to ensure that all Unicode characters translate into valid C function names. We use the underscore (“_”) character as the substitute for the slash (“/”) in fully qualified class names. Since a name or type descriptor never begins with a number, we can use _0

, ..., _9 for escape sequences, as Table 2-1 illustrates: 

Table 2-1 Unicode Character Translation
Escape SequenceDenotes
_0XXXXa Unicode character XXXX.
Note that lower case is used
to represent non-ASCII
Unicode characters, e.g.,
_0abcd as opposed to
_0ABCD.
_1the character “_”
_2the character “;” in signatures
_3the character “[“ in signatures

Both the native methods and the interface APIs follow the standard library-calling convention on a given platform. For example, UNIX systems use the C calling convention, while Win32 systems use __stdcall.

Native Method Arguments

    The JNI interface pointer is the first argument to native methods. The JNI interface pointer is of type JNIEnv. The second argument differs depending on whether the native method is static or nonstatic. The second argument to a nonstatic native method is a reference to the object. The second argument to a static native method is a reference to its Java class.

    The remaining arguments correspond to regular Java method arguments. The native method call passes its result back to the calling routine via the return value. Chapter 3 describes the mapping between Java and C types.

Code Example 2-1 illustrates using a C function to implement the native method f. The native method f is declared as follows:

package pkg; 

class Cls {

     native double f(int i, String s);

     ...

}

    The C function with the long mangled name Java_pkg_Cls_f_ILjava_lang_String_2 implements native method f:

Code Example 2-1 Implementing a Native Method Using C
jdouble Java_pkg_Cls_f__ILjava_lang_String_2 (
     JNIEnv *env,        /* interface pointer */
     jobject obj,        /* "this" pointer */
     jint i,             /* argument #1 */
     jstring s)          /* argument #2 */
{
     /* Obtain a C-copy of the Java string */
     const char *str = (*env)->GetStringUTFChars(env, s, 0);

     /* process the string */
     ...

     /* Now we are done with str */
     (*env)->ReleaseStringUTFChars(env, s, str);

     return ...
}

    Note that we always manipulate Java objects using the interface pointer env . Using C++, you can write a slightly cleaner version of the code, as shown in Code Example 2-2:

Code Example 2-2 Implementing a Native Method Using C++
extern "C" /* specify the C calling convention */ 

jdouble Java_pkg_Cls_f__ILjava_lang_String_2 (

     JNIEnv *env,        /* interface pointer */

     jobject obj,        /* "this" pointer */

     jint i,             /* argument #1 */

     jstring s)          /* argument #2 */

{

     const char *str = env->GetStringUTFChars(s, 0);

     ...

     env->ReleaseStringUTFChars(s, str);

     return ...

}

    With C++, the extra level of indirection and the interface pointer argument disappear from the source code. However, the underlying mechanism is exactly the same as with C. In C++, JNI functions are defined as inline member functions that expand to their C counterparts.

二、命名規則

    從官網文件我們瞭解到JNI函式的命名規則:

  • java程式碼中的函式宣告需要新增native關鍵字。
  • native中的函式命名規則Java_包名_類名_自定義函式名_簽名。其中包名中的“.”,需要修改成“_”。

    注:VM檢查與本地庫中駐留的方法匹配的方法名稱。VM首先查詢短名稱; 即沒有引數簽名的名稱。然後它查詢長名稱,這是帶有引數簽名的名稱。只有當本地方法被另一個本地方法過載時,程式設計師才需要使用長名稱。但是,如果本機方法與非本機方法具有相同的名稱,則這不需要。

  • JNI介面指標是本地方法的第一個引數。JNI介面指標的型別是JNIEnv第二個引數根據本地方法是靜態還是非靜態而不同。非靜態本地方法的第二個引數是對該物件的引用。靜態本地方法的第二個引數是對其Java類的引用。其餘的引數對應於Java方法引數。
  • java方法引數和返回值需要根據對照表進行相應的轉換,請參照:java和jni型別對照表
  • 由於jni函式名對映成java函式名的時候是依靠“_”來間隔包、類、方法的,如果你的函式中有“_”字元的話,jni必須能夠區分函式名中的“_”是字元還是分隔符,所以在函式名前面需要加1用於區分。

三、android studio快速生成標頭檔案

  • 開啟Terminal(控制檯)

    View->Tool Windows->Terminal。

  • 跳轉到目錄:cd app/src/main/java

    

  • 生成JNI標頭檔案

    在控制檯輸入javah -d . -jni xxxx命令,其中“xxxx”是完整的類路徑,例如“com.zzy.ndkdemo.MainActivity”