1、JNI的全称是Java Native Interface,中文翻译过来就是Java本地调用,这种机制允许我们能够在Java中调用其他的语言。
2、在Eclipse中新建一个最简单的工程HelloWorld,新建一个类testHello:
其中native函数就是我们要用C/C++来进行编写的部分。
package com.wxg;
public class testHello {
public native void test();
public static void main(String[] args){
new testHello().test();
}
}
3、命令行进入到这个工程的src文件夹下
先将源文件编译成class文件
D:\android\ServerProject\HelloWorld\src>javac com\wxg\testHello.java
然后用javah命令将java文件中的native函数转化成对应的头文件
D:\android\ServerProject\HelloWorld\src>javac com\wxg\testHello.java
在src文件夹下就能看到一个头文件com_wxg_testHello,会发现这个头文件的命名是和Java中的类的命名是一致的,只不过这里用下划线来代替了Java中的点号。打开这个文件,会发现起代码如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_wxg_testHello */
#ifndef _Included_com_wxg_testHello
#define _Included_com_wxg_testHello
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_wxg_testHello
* Method: test
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_wxg_testHello_test
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
头文件中的JNIEXPORT和JNICALL表示这个函数是要被JNI所调用的。剩下的就是常见的C/C++的头文件声明相关。
4、实现这个函数并编译成dll/so文件。
需要注意的是,由于C/C++不像Java那样是跨平台的,所以如果用的是64位的jdk,就需要使用相应的64位的编译器(gcc之类的),如果是32位的jdk,自然也就需要用32位的编译器。
我是用CodeBlocks的,新建一个“Dynamic Link Library”工程,然后将之前生成的头文件拷贝到工程的源文件夹中并将其添加到这个工程中去,我用的编译器是Ming-GW 64-bit Compiler。还有就是需要将%JAVA_HOME%\include\jni.h和%JAVA_HOME%\include\win32\jni_md.h也拷贝到这个工程的源文件夹中去并添加到工程中。添加完后的工程目录结构如下
然后开始实现头文件中的函数,新建文件com_wxg_testHello.c,实现的代码比较简单:
#include "com_wxg_testHello.h"
#include "stdio.h"
JNIEXPORT void JNICALL Java_com_wxg_testHello_test
(JNIEnv * env, jobject obj){
printf("hello world\n");
}
如果提示有错误,可以检查下是否是因为在头文件中需要将#include <jni.h>改为#include "jni.h",是否需要将jni_md.h也加到头文件中。
编译成功,能在工程的bin/debug目录下发现多了一个test.dll文件。
5、将这个动态文件test.dll文件拷贝到Hello World工程的根目录(注意是项目的根目录而不是源文件的根目录)下,然后在testHello.java中加入下面一句
static{
System.loadLibrary("test");
}
这里将dll文件拷贝到项目根目录纯粹是为了测试而用。实际项目中,需要不断地修改C/C++文件,Java这边也需要测试,这样生成一次dll文件就要拷贝一次会比较麻烦。所以如果是实际使用的话,可以在系统的Path环境变量中加入test.dll文件的路径。
运行完可以得到正确结果:
6、上面说的是Windows下如何将文件编译成dll文件。如果是在Linux环境下,则需要编译成so文件,这是Linux下的动态链接库的格式。
需要执行以下命令来编译成动态链接库
gcc com_wxg_testHello.c -fPIC -shared -o libtest.so
7、介绍给大家一个工具,可以查看dll文件中所有的函数相关的信息。先看看界面
可以通过这个工具来查看某个dll文件中对应的函数以及命名什么的。其实可以猜想的是JNI是通过查看dll中的函数名来进行相应的调用的。
Java中某类com.wxg.testHello的test函数
在dll中的命名应该是Java_com_wxg_testHello_test,参数可以自己参照jni的标准,这样其实可以省去javah这一步~~