JNI使用的一些实现

下面总结在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的朋友提供一些帮助,也希望我们能共同探讨更深入的知识。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值