一、概述
通过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函数。