一、概述
通過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函數。