我们在HelloWorld.java中定义的private native void print()调用时,
怎么就会调用到我们底层的Java_com_worthcloud_HelloWorld_print(JNIEnv *env,jobject obj)函数呢?这里先大概了解一下Java中我们本地库的加载
方式:System.loadlibrary(libraryname)。该函数会在适当的路劲加载动态库文件,然后通过类似于dlsym(handle,"JNI_OnLoad")方法来执行JNI_OnLoad
函数。这样我们就可以在JNI_OnLoad()这样一个函数中做一些事情以影响后续的程序代码执行。我们这章介绍的通过函数名对应表的方式来加载native方法
就是在这里面做了些文章的。
在Java运行时,其内部会维持一个native函数库表,这里我们暂且称为native_sym_tbl,该开始这个表示空的。当在执行到某一个native方法时,例如执行到
new HelloWorld().print()这个natvie方法时,就从native_sym_tbl这个表中查找该print函数对应的底层实现函数原型,而此时该表为空,肯定查找不到,这时就会
采用默认的Java_完整类名_函数名()的方式在动态加载库中查找该函数,针对前面的print()这个函数,就会执行如下查找Java_com_worthcloud_HelloWorld_print()
方法,然后执行该函数,没有找到则直接报错。那么,如果我们通过适当的方法,预先填好native_sym_tbl这个表,则在后续的执行中则可以直接对应到底层的
实现函数,并且这样还未我们带来了一个副产品:可以将Java中声明的native方法名称映射为我们自己的名称,而不需要按照其默认的方式。
看如下实现:
HelloWorld.java
- package com.worthcloud;
-
- class HelloWorldUtils
- {
- public native void print();
- }
-
-
- class Prompt
- {
- public native String getLine(String prompt);
- }
-
-
- public class HelloWorld {
-
-
- private native void print();
- public native String getLine(String prompt);
-
- public static void main(String[] args) {
-
- new HelloWorldUtils().print();
-
- new HelloWorld().print();
-
- while(true)
- System.out.println("Output:"+new Prompt().getLine("Input:"));
- }
-
- static
- {
- System.loadLibrary("helloworld");
- }
-
-
- }
JNI_HelloWorld.c:
-
"code" class="cpp">#include
- #include
- #include "jni_helloworld.h"
-
-
- #define HELLOWORLDUTILS_CP "com/worthcloud/HelloWorldUtils"
- #define HELLOWORLD_CP "com/worthcloud/HelloWorld"
- #define PROMPT_CP "com/worthcloud/Prompt"
-
-
-
-
-
-
-
- JNIEXPORT void JNICALL JNI_HelloWorldUtils_print(JNIEnv *env, jobject obj)
- {
- printf("Hello World - (utils)\n");
- fflush(stdout);
- }
-
-
-
-
-
-
- JNIEXPORT void JNICALL JNI_HelloWorld_print(JNIEnv *env, jobject obj)
- {
- printf("Hello World\n");
- fflush(stdout);
- }
-
-
-
-
-
-
- JNIEXPORT jstring JNICALL JNI_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
- {
- char buf[128];
- const char *str;
- str = (*env)->GetStringUTFChars(env, prompt, NULL);
- if (str == NULL)
- return NULL;
-
- printf("%s", str);
- fflush(stdout);
- (*env)->ReleaseStringUTFChars(env, prompt, str);
-
-
-
-
- scanf_s("%s", buf);
-
- return (*env)->NewStringUTF(env, buf);
- }
-
-
- static JNINativeMethod gHelloWorldUtilsMethods[] = {
- {
- "print",
- "()V",
- (void *)JNI_HelloWorldUtils_print
- }
- };
-
- static JNINativeMethod gHelloWorldMethods[] = {
- {
- "print",
- "()V",
- (void *)JNI_HelloWorld_print
- }
- };
-
- static JNINativeMethod gPromptMethods[] = {
- {
- "getLine",
- "(Ljava/lang/String;)Ljava/lang/String;",
- (void *)JNI_Prompt_getLine
- }
- };
-
-
-
-
-
-
-
-
-
- static int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *pMethods, int nMethods)
- {
- jclass clazz;
-
- if ((clazz = (*env)->FindClass(env, className)) == NULL)
- return -1;
-
- if ((*env)->RegisterNatives(env, clazz, pMethods, nMethods) != JNI_OK)
- return -2;
-
- return 0x0;
- }
-
-
-
-
-
-
-
-
-
- JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
- {
- JNIEnv *env = NULL;
- jint result = 0;
-
- if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_4) != JNI_OK || env == NULL)
- {
- result = -1;
- goto end;
- }
-
- if (registerNativeMethods(env, HELLOWORLDUTILS_CP, gHelloWorldUtilsMethods,
- sizeof(gHelloWorldUtilsMethods) / sizeof(JNINativeMethod)) < 0)
- {
- result = -2;
- goto end;
- }
-
- if (registerNativeMethods(env, HELLOWORLD_CP, gHelloWorldMethods,
- sizeof(gHelloWorldMethods) / sizeof(JNINativeMethod)) < 0)
- {
- result = -3;
- goto end;
- }
-
- if (registerNativeMethods(env, PROMPT_CP, gPromptMethods,
- sizeof(gPromptMethods) / sizeof(JNINativeMethod)) < 0)
- {
- result = -4;
- goto end;
- }
-
-
- result = JNI_VERSION_1_4;
-
- end:
- if (result < 0)
- {
- printf("JNI_OnLoad failure(ret:%d)\n", result);
- }
- return result;
- }
-
-
-