JNI 开发一般流程

JNI(Java Native Interface),Java 和C/C++ 相互调用的一套API,教程相对简单,入门系列。

一般流程

  1. 编写native方法
  2. javah命令,生成.h头文件
  3. 复制.h头文件到cpp工程中,复制JDK里面的jni.h和jni_md.h文件到工程中
  4. 实现.h头文件中声明的函数
  5. 生成dll文件给Java调用
  6. 配置动态库给环境变量

1.编写native方法

1
2
3
4
5
6
7
8
9
public class JniTest{

//关键字native方法
public native static String getStringFromC();

public static void main(String[] args){

}
}

2.生成头文件

使用javah命令生成.h头文件,头文件代码自动生成。规则:(C的函数名称:Java_完整类名_函数名)

1
2
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_jni_JniTest */
#ifndef _Included_com_jni_JniTest #define _Included_com_jni_JniTest #ifdef __cplusplus extern "C" { #endif /* * Class: com_jni_JniTest * Method: getStringFromC * Signature: ()V */ JNIEXPORT jstring JNICALL Java_com_jni_JniTest_getStringFromC (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif

####生成头文件可能遇到的问题

  • 使用javah命令提示找不到类文件

    我的工作路径是C:\Users\Administarator\Desktop\JniStudy\java_jni,下面就是src和bin,不要直接进入src目录使用javah命令,正确的命令行应该是:

    1
    javah -classpath bin -d jni com.jni.JniTest

3.复制头文件

准备头文件,头文件有刚刚生成的.h文件以及拷贝以下路径的.h头文件。路径分别为:

1
2
JDK路径\include\win32\jni_md.h
JDK路径\include\jni.h

然后在Visual Studio使用添加项来添加头文件,如果还有报错,
将生成的头文件.h的#include <jni.h>改为#include “jni.h”

4.实现.h头文件中的函数

1
2
3
4
5
6
7
#include "con_jni_JniTest.h"

//函数实现,拷贝.h方法声明,补充参数变量
JNIEXPORT jstring JNICALL Java_com_jni_JniTest_getStringFromC
(JNIEnv *env, jclass jcls){
//将C的字符串转换为一个Java的字符串 return (*env)->NewStringUTF(env,"Hello JNI!");
}

5.生成dll动态库给java调用

右键Visual studio项目 -> 属性 -> 配置类型(动态库dll),然后生成解决方案。

为什么是dll呢,windows下,使用dll,如果是在android下,就要使用.so。dll动态库生成了之后,要在环境变量中配置动态库的路径,不然eclipse找不到动态库,配置了之后,要重启eclipse。

6.加载动态库

1
2
3
4
5
6
7
8
9
10
11
12
13
public class JniTest{

//关键字native方法
public native static String getStringFromC();

public static void main(String[] args){
System.out.print(getStringFromC());
}

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

最后当然是输出 Hello JNI!

JNIEnv

1
2
3
4
5
6
JNIEXPORT jstring JNICALL Java_com_jni_JniTest_getStringFromC
(JNIEnv *env, jclass jcls){
//将C的字符串转换为一个Java的字符串 return (*env)->NewStringUTF(env,"Hello JNI!");
//将C++ 的字符串转换为一个Java的字符串
return env -> NewStringUTF("Hello JNI!");
}
1
struct JNINativeInterface_;

struct JNIEnv_;

#ifdef __cplusplus
typedef JNIEnv_ JNIEnv;
#else
typedef const struct JNINativeInterface_ *JNIEnv;
#endif

在C和C++中env的使用方式不相同,并且他们的定义也不相同。在C中,JNIEnv是一个结构体指针别名,env是一个二级指针;在C++中,JNIEnv是一个结构体别名,env是一个一级指针。函数执行过程中,需要JNIEnv,C++为什么没有传入,因为有this可以拿到。C++只是对C的那一套做了一层封装。

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器