JNI编程简单实践
JNI简介
在维基百科中对JNI的定义如下:JNI (Java Native Interface,Java本地接口)是一种编程框架,使得Java虚拟机中的Java程序可以调用本地应用/或库,也可以被其他程序调用。 本地程序一般是用其它语言(C、C++或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序。在Java语言中native方法就是使用JNI技术来实现的,通过JNI技术可以调用底层C++或C语言编写的代码。
简单示例
HelloWorld
public class HelloWorld {
public native void displayHelloWorld();
private int a = 0;
static {
System.loadLibrary("HelloWorldImpl");
}
public static void main(String[] args) {
HelloWorld helloWorld = new HelloWorld();
System.out.println("a1\t"+helloWorld.a);
helloWorld.displayHelloWorld();
System.out.println("a2\t"+helloWorld.a);
}
}
首先定义一个HelloWorld类,其中有一个private变量a和一个native方法displayHelloWorld,通过javac对java文件进行编译生成.class文件,随后使用javah -jni HelloWorld 指令生成一个HelloWorld.h文件。
HelloWorld.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: displayHelloWorld
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
生成HelloWorld.h文件后需要将JAVA_HOME\inclide下的jni.h文件导入到HelloWorld.h文件同一文件夹中,然后再将JAVA_HOME\inclide\win32下的jni_md.h文件也导入到HelloWorld.h同一文件夹中,这样才能进行编译。其中JNIEXPORT 的原型的JNICALL说明函数的参数由右向左入栈,JNIEXPORT表示外部可以调用该函数。
然后编写一个新的文件HelloWorld.cpp,同时导入HelloWorld.h。
HelloWorld.cpp
#include "HelloWorld.h"
#include <stdio.h>
int temp = 0;
JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld
(JNIEnv * env, jobject thiz) {
printf("Hello world!");
return;
}
然后使用gcc编译器或者vs自动的编译器对HelloWorld文件进行编译生成HelloWorldImpl.dll文件。
gcc -Wall -shared HelloWorld.cpp -o HelloWorldImpl.dll
运行java HelloWorld就可以看到频幕上打印出了Hello World
变量获取和赋值
HelloWorld.java和上文一样,改变HelloWorld.cpp文件
HelloWorld.cpp:
#include "HelloWorld.h"
#include <stdio.h>
int temp = 0;
JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld
(JNIEnv * env, jobject thiz) {
jfieldID id;
jclass c;
c = env->FindClass("HelloWorld");
if (c==NULL)
{
printf("FindClass failed");
return;
}
id = env -> GetFieldID( c, "a", "I");
if (id==NULL)
{
printf("GetFiledID failed");
return;
}
env->SetIntField(thiz, id, 20);
return;
}
在新的cpp文件中定义了一个jfield和jclass,通过FindClass文件找到HelloWorld的class,然后使用GetDieldID获取a属性的id,然后再该object中找到a的位置,然后对a的值进行修改,调用SetIntField函数,可以对当前对象下的a属性进行修改,将a的值修改为20。
运行java HelloWorld可以看到第一个a为0第二个a为20。