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的朋友提供一些帮助,也希望我们能共同探讨更深入的知识。
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的朋友提供一些帮助,也希望我们能共同探讨更深入的知识。
相关文章推荐
- 市面上所有号称"虚拟机","防火墙"的实时监控杀毒软件无一不是使用的IFSHOOK技术.但是同时也有一些朋友不断写MAIL给我打听如何实现读写的监控.下面给出用VTOOLSD写的代码.也就是所有实时杀毒软件的奥秘.同时,很多拦截文件操作的软件,例如对目录加
- .Net中VSS实现版本控制管理的一些使用方法
- Java进阶: 使用 Jni 调用 Dll 的实现(使用VS2008 生成Dll)
- 使用JNI技术实现JAVA程序调用dll
- 使用C++实现JNI接口需要注意的事项
- VSS实现版本控制管理的一些使用方法
- Android使用JNI实现Java与C之间传递数据
- 编写的vs2005水晶报表程序在vs2008下正常使用的一些实现方法
- 使用C++实现JNI接口需要注意的事项
- Android使用JNI实现Java与C之间传递数据
- .Net中VSS实现版本控制管理的一些使用方法
- 编写的vs2005水晶报表程序在vs2008下正常使用的一些实现方法
- 编写的vs2005水晶报表程序在vs2008下正常使用的一些实现方法
- 下面简单使用Jquery来操作iframe的一些记录,这个使用纯JS也可以实现。
- 编写的vs2005水晶报表程序在vs2008下正常使用的一些实现方法(转)
- VSS实现版本控制管理的一些使用方法
- 使用OmniORB出现的一些问题及已实现的解决方法
- 使用JNI技术实现JAVA程序调用dll
- 使用JNI技术实现JAVA程序调用dll
- 使用宏定义,简单实现jni函数命名