您的位置:首页 > 其它

JNI使用的一些实现

2017-04-10 14:12 344 查看
下面总结在Linux下使用JNI的一些心得(开发工具MyEclipse)。

Java类testjni主要用来加载.so的c程序,其中方法Test与c程序中的编码与解码函数对应,testjni.java代码如下:

package test2.a.b; //源码所在包

public class testjni{

static {

System.loadLibrary("ttate"); //载入ttate.so

}

public native int Test(); //本地函数,与ttate.so中的函数对应

}

将上面的testjni.java编译成.h文件,这里要小心,在linux MyEclipse下我们应该将当前目录cd到工程的src下,使用"javah -jni

test2.a.b.testjni"指令,使编译出的.h文件名为“test2_a_b_testjni.h”,这么做都是因为在MyEclipse下我们将源码都放在了test2.a.b包下,否则会提示'UnsatisfiedLinkError"错误。注意:包名中的点“.”会变为下划线"_"。编译好的test2_a_b_testjni.h不要去改动它,因为是机器自动生成的,改动后可能会出现连接失败错误,test2_a_b_testjni.h的源码如下:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class test2_a_b_testjni */

#ifndef _Included_test2_a_b_testjni

#define _Included_test2_a_b_testjni

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class: test2_a_b_testjni

* Method: Test

* Signature: ()I

*/

JNIEXPORT jint JNICALL Java_test2_a_b_testjni_Test

(JNIEnv *, jobject);

#ifdef __cplusplus

}

#endif

#endif

以上标记红色的函数名要与你的C源码中的函数完全对应,一定不能有差错。我的C程序的部分源码如下:

#include <iostream>

#include "test2_a_b_testjni.h" //包含上面编译出的头文件

#include <sys/time.h>

#include <sys/stat.h>

#include <string.h>

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <signal.h>

using namespace std;

int Test();

char* jstringToString(JNIEnv *env, jstring jstr) //将jstring转换为string的方法

{

char* temp = NULL;

jclass clsstring = env->FindClass("java/lang/String");

jstring strencode = env->NewStringUTF("utf-8"); //使用utf-8可以处理中文,但用gb2312却不行,不知为什么

jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");

jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);

jsize alen = env->GetArrayLength(barr);

jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);

if (alen > 0)

{

temp = (char*)malloc(alen + 1);

memcpy(temp, ba, alen);

temp[alen] = 0;

}

env->ReleaseByteArrayElements(barr, ba, 0);

return temp;

}

JNIEXPORT jint JNICALL Java_test2_a_b_testjni_Test(JNIEnv *, jobject)

{

return Test();

}

int Test()

{

printf("see you!\n");

return 11;

}

使用下面的指令将ttate.c编译成ttate.so文件:

g++ -I /usr/java/jdk1.8.0_121/include -I /usr/java/jdk1.8.0_121/include/linux -fPIC -c
ttate.c

g++ -shared -W1,-soname,ttate.so.1 -o
ttate.so.1.0
ttate.o

cp ttate.so.1.0
ttate.so

将生成的.so文件放入系统JDK的安装目录下,具体路径为:/..../jdk1.8.0_121/jre/lib/i386

最好在/usr/lib下放一个.so库文件

最后MyEclipse工程中test2.a.b;包只需要如下的文件:

testjni.java, testjni.class, test2_a_b_testjni.h

测试时直接在包中新建一个测试类,new一个testjni对象,在调用其native方法即可,我的测试类如下:

package test2.a.b;

public class testjni{

public static void main(String[] args) {

testjni tEn = new
testjni();

tEn.Test();//调用native方法

}

}

至此完成!过程中C代码一定要保证没有错误,其间就因为C代码出现数组越界、长度不够或内存泄露的问题,产生不少错误,拖延了项目进度。此外,特别注意的就是源码在包中时,一定要注意包也要加入到.h文件名中,否则MyEclipse不知道从哪里找都相关文件(通常我们认为源码在一个包下,系统就会自动找到同一包中的其他文件,但.h文件好像不是这样的)。

希望能给初用JNI的朋友提供一些帮助,也希望我们能共同探讨更深入的知识。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: