歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> JNI通過動態注冊實現native函數

JNI通過動態注冊實現native函數

日期:2017/3/1 9:05:50   编辑:Linux編程

一、概述
通過javah工具將java代碼中的native聲明的函數生成標准的C/C++函數頭,每個函數的名字都很長(Java_包名_類名_函數名),這樣C/C++函數的函數名就是定死的,不能修改,否則java找不到函數。這裡還有種方式,通過注冊的方式將C/C++的函數與java中的native函數進行一一對應的,函數名可以任意書寫。

二、代碼實現
SimpleJni.java

package com.bt.jni;

public class SimpleJni {

static {
System.out.println("[java]static code block, start load shared library....");
System.loadLibrary("simpleJni");
System.out.println("[java]load library end....");
}

static native int add(int a, int b);

public static void main(String args[]) {
System.out.println("[java] in main()...");
System.out.println("[java] 3 + 5 = " + SimpleJni.add(3, 5));
System.out.println("[java] main() end...");
}

}

simple_jni.c
#include "jni.h"
#include <stdio.h>


const char *classPathName = "com/bt/jni/SimpleJni";

/**
native 函數的實現
**/
jint myadd(JNIEnv *env, jobject thiz, jint a, jint b)
{
return a + b;
}

static JNINativeMethod methods[] = {
//{native函數名,函數簽名, C中函數實現名}
{"add", "(II)I", (void*)myadd},
};

int registerNatives(JNIEnv *env)
{
jclass clazz;

//根據類的全路徑,獲得類的字節碼信息
clazz = (*env)->FindClass(env, classPathName);
if (NULL == clazz) {
printf("[C] FindClass() failed...\n");
goto failed;
}

//將c函數與字節碼中的native函數進行映射
if (0 > (*env)->RegisterNatives(env, clazz, methods, sizeof(methods)/sizeof(methods[0]))) {
printf("[C] RegisterNatives() failed...\n");
goto failed;
}

return JNI_TRUE;

failed:
return JNI_FALSE;
}

/**
java 在加載動態庫的時候,自動調用此函數,注冊native函數
**/
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv *env = NULL;
jint result = -1;
void **env_p = NULL;

printf("[C] start register native func...\n");

env_p = (void**)&env;

//首先從java虛擬機中獲得env
if (JNI_OK != (*vm)->GetEnv(vm, env_p, 0x00010004)) {
printf("[C] GetEnv() failed...will exit\n");
goto err;
}

//通過env進行函數的注冊
if (JNI_TRUE != registerNatives(env)) {
printf("[C] register func failed...will exit\n");
goto err;
}

result = 0x00010004;
printf("[C] register end...\n");
err:
return result;
}

操作步驟
1.首先編寫SimpleJni.java和simpel_jni.c
2.編譯java和c文件
$ java -d . SimpleJni.java
$gcc -fPIC -I$JAVA_HOME/include/ -I$JAVA_HOME/include/linux/ -o libsimpleJni.so simple_jni.c

3.執行
$java -Djava.library.path=. com.bt.jni.SimpleJni

結果:
[java]static code block, start load shared library....
[C] start register native func...
[C] register end...
[java]load library end....
[java] in main()...
[java] 3 + 5 = 8
[java] main() end...

根據結果可知,java首先執行靜態代碼塊,其中在加載動態庫的時候,自動調用JNI_OnLoad函數,建立native函數和c中的函數映射關系,最後進入main函數。

Copyright © Linux教程網 All Rights Reserved