Java jni本意是Java native interface(Java本地接口),是为了方便Java调用c、c++等本地代码所封
装的一层接口。大家都知道,Java的优点是跨平台,但是作为优点的同时,其在本地交互的时候就编程了缺点。
Java的跨平台特性导致其本地交互的能力不够强大,一些和操作系统相关的特性Java无法完成,于是Java提供了
jni专门用于和本地代码交互,这样就增强了Java语言的本地交互能力。
通过Java jni,用户可以调用用c、c++所编写的native code。在html5视频的开发中就采用了jni,
android只用于ui的显示,其业务逻辑都是通过native code所完成的,android代码只是负责通过jni和native进
行交互。
通过Java jni来调用native code,需要如下几个步骤:
1.声明native接口函数,语法如下:public native static void set(int i);
其中native是Java的关键字,被native修饰的函数都是本地函数的接口,其具体功能要被native code来
实现。
//testdll.java
public class testdll
{
static
{
System.loadLibrary("my");
}
public native static int get();
public native static void set(int i);
public static void main(String[] args)
{
testdll test = new testdll();
test.set(3721);
System.out.println(test.get());
}
}
2.用javah命令导出Java jni中定义的本地方法的声明,这个是.h格式的头文件
首先用javac编译出class文件,然后在用javah导出头文件,我们发现导出的头文件,其函数声明发生了
变化,其中jint是jni定义的用来和c/c++交互的数据类型,可以当作int来用。
//testdll.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class testdll */
#ifndef _Included_testdll
#define _Included_testdll
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: testdll
* Method: get
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_testdll_get
(JNIEnv *, jclass);
/*
* Class: testdll
* Method: set
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_testdll_set
(JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif
3. 实现Java jni中定义的native methods
有了头文件以后,就可以用本地函数去实现头文件中声明的native函数了,通常用c和c++来实现native
函数。
//my.c
#include "jni.h"
#include "testdll.h"
#include<stdio.h>
static int i;
JNIEXPORT jint JNICALL Java_testdll_get(JNIEnv *a, jclass b)
{
return i;
}
JNIEXPORT void JNICALL Java_testdll_set(JNIEnv *a, jclass b, jint j)
{
FILE *f;
f=fopen("my.txt","a+");
fwrite("嘿嘿你好啊xixi",1,14,f);
fclose(f);
i = j;
}
4.将native code编译成shared library供Java调用,针对Linux来说 就是.so文件,针对Windows来说就是.dll文
件,Linux下用g++、gcc进行编译,这里不对其进行介绍,毕竟不难。对Windows来说,编译生成dll一般是通过vc
来完成的。Windows下的动态链接库分为win32 dll和mfc dll,其中win32 dll可以供各种语言调用,而mfc dll则
会受到一些限制。这里介绍win32 dll。
生成一个win32 dll,要定义被导出的函数,有两种方式,函数名称前加_declspec(dllexport)或者定义def
文件,然后用vc进行编译,这样做并不算复杂,但是我发现了一种更容易的方法,我们只需要按照c/c++的语法规
范实现native函数,不需要定义被导出的函数,然后调用vc的编译工具cl.exe就可以了。
首先将testdll.h和my.c拷贝到Microsoft Visual Studio x.x\VC\bin中,同时将jdk中include目录中的所有文件
也都拷贝到Microsoft Visual Studio x.x\VC\bin中(这样做不是必须的,但是如果不这样,你调用cl命令的时
候就要带上一大串路径信息),接着调出vs再带的命令行工具,进入bin目录,然后执行cl -I . -LD my.c -
Femy.dll(.表示当前目录,I表示将在当前目录搜索包含的头文件,-LD后面表示源文件,-Fe后面紧跟的是目标文
件),ok,my.dll生成了,将my.dll拷贝到Java文件所在的目录,执行Java命令,成功执行。
上面只是个简单的示例,实际开发中还会有一些需要注意的问题,比如各种类型参数的传递,native code调用
dll或so的情况,这里就不做介绍了,完毕。