JNI:通过函数名对应表的方式来加载对应的native方法

       接上一篇  <<Eclipse + vs2013 编写第一个 JNI HelloWorld>>  ,读者一定很奇怪我们在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) {
		// TODO Auto-generated method stub
		new HelloWorldUtils().print();
	
		new HelloWorld().print();
		
		while(true)
			System.out.println("Output:"+new Prompt().getLine("Input:"));
	}

	static
	{
		System.loadLibrary("helloworld");
	}
	

}



JNI_HelloWorld.c:
#include <jni.h>
#include <stdlib.h>
#include "jni_helloworld.h"


#define HELLOWORLDUTILS_CP		"com/worthcloud/HelloWorldUtils"
#define HELLOWORLD_CP			"com/worthcloud/HelloWorld"
#define PROMPT_CP				"com/worthcloud/Prompt"


/**
* Class: com_worthclould_HelloWorldUtils_print
* Method: print
* Signature: ()V
*/
JNIEXPORT void JNICALL JNI_HelloWorldUtils_print(JNIEnv *env, jobject obj)
{
	printf("Hello World - (utils)\n");
	fflush(stdout);
}

/**
* Class: com_worthclould_HelloWorld_print
* Method: print
* Signature: ()V
*/
JNIEXPORT void JNICALL JNI_HelloWorld_print(JNIEnv *env, jobject obj)
{
	printf("Hello World\n");
	fflush(stdout);
}

/**
* Class: com_worthcloud_Prompt
* Method: getLine
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
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;	/*OutOfMemoryError already thrown*/

	printf("%s", str);
	fflush(stdout);
	(*env)->ReleaseStringUTFChars(env, prompt, str);

	/**
	* We assume here that the user does not type more than 127 characters
	*/
	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
	}
};

/**
 * description: 针对类名,注册多个native 接口函数
 * 
 * env: 代表Java环境,通过这个环境可以调用JNIEnv中的相关方法
 * className: Java类名称
 * pMethods: 接口函数表
 * nMethods: 接口函数中函数的个数
*/
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;
}


/**
 * 方法名称规定: jni 入口函数
 * 
 * 参数介绍:
 * vm: 虚拟机指针
*/

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



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值