oracle jni getintarrayelements,jni调用C和C++

摘要:

java程序可以通过jni调用C或者C++的库。本文实现了一个简单的jni调用例子。

已经在工作中碰到了两个这样的例子了,项目用java,但需要调用C/C++的库。之前一个是用java写hadoop的job,但是调用的算法是用C++实现的,使用的是jni。现在好像jni在android上面也有用到,但是我不了解。我自己也不懂java,但实际工作中有的时候也要看看java代码。所以决定写一个简单的jni例子,了解一下jni怎么完成C/C++调用的。

对于jni的内部实现,我也是不求甚解。编写一个java程序

jni调用的java代码 (Sample1.java) download

public class Sample1 {public native int intMethod(int n);public native boolean booleanMethod(boolean bool);public native String stringMethod(String text);public native int intArrayMethod(int[] intArray);public static void main(String[] args) {System.loadLibrary("Sample1");Sample1 sample = new Sample1();int square = sample.intMethod(3);System.out.println("intMethod: " + square);boolean bool = sample.booleanMethod(true);System.out.println("booleanMethod: " + bool);String text = sample.stringMethod("java");System.out.println("stringMethod: " + text);int sum = sample.intArrayMethod(new int[] { 1, 1, 2, 3, 5, 8, 13 });System.out.println("intArrayMethod: " + sum);}}

然后编译java文件

javac Sample1.java

编译完以后, 使用下面的命令生成jni调用的头文件

javah -classpath ./ -jni Sample1

生成的头文件为Sample1.h, 就是下面C/C++实现的函数的声明, 注意:Sample1.h是自动生成的

jni生成的头文件 (Sample1.h) download

/* DO NOT EDIT THIS FILE - it is machine generated */#include /* Header for class Sample1 */#ifndef _Included_Sample1#define _Included_Sample1#ifdef __cplusplusextern "C" {#endif/** Class: Sample1* Method: intMethod* Signature: (I)I*/JNIEXPORT jint JNICALL Java_Sample1_intMethod(JNIEnv *, jobject, jint);/** Class: Sample1* Method: booleanMethod* Signature: (Z)Z*/JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod(JNIEnv *, jobject, jboolean);/** Class: Sample1* Method: stringMethod* Signature: (Ljava/lang/String;)Ljava/lang/String;*/JNIEXPORT jstring JNICALL Java_Sample1_stringMethod(JNIEnv *, jobject, jstring);/** Class: Sample1* Method: intArrayMethod* Signature: ([I)I*/JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod(JNIEnv *, jobject, jintArray);#ifdef __cplusplus}#endif#endif

有了头文件后,就可以实现这些调用的C/C++代码

C++实现的Sample1.cpp (Sample1.cpp) download

#include "Sample1.h"#include #include JNIEXPORT jint JNICALLJava_Sample1_intMethod(JNIEnv *env, jobject obj, jint num){return num * num;}JNIEXPORT jboolean JNICALLJava_Sample1_booleanMethod(JNIEnv *env, jobject obj, jboolean boolean){return !boolean;}JNIEXPORT jstring JNICALLJava_Sample1_stringMethod(JNIEnv *env, jobject obj, jstring jstr){const char *str = env->GetStringUTFChars(jstr, 0);char cap[128];strcpy(cap, str);env->ReleaseStringUTFChars(jstr, str);char* ptr = cap;while (*ptr != '\0'){*ptr = toupper(*ptr);ptr++;}return env->NewStringUTF(cap);}JNIEXPORT jint JNICALLJava_Sample1_intArrayMethod(JNIEnv *env, jobject obj, jintArray array){int i, sum = 0;jsize len = env->GetArrayLength(array);jint *body = env->GetIntArrayElements(array, 0);for (i=0; iReleaseIntArrayElements(array, body, 0);return sum;}

然后调用下面的命令生成动态链接库(系统:ubuntu 12.04,gcc编译)

g++ -I /usr/lib/jvm/java-1.6.0-openjdk/include/ -I /usr/lib/jvm/java-1.6.0-openjdk/include/linux/ Sample1.cpp -fPIC -shared -o libSample1.so

具体的jdk的路径应该是和本地的相适应的。

然后运行java程序

java Sample1

运行结果如下

278edbe6381e79eeeb519865bc236fda.png

图中加入了一个环境变量的声明,export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH, 当java加载动态链接库时,会在本地路径下找libSample1.so。

上面是调用C++的代码,C实现的代码如下

C语言实现的Sample1.c (Sample1.c) download

/** the difference between C++ and c like this:*const char *str = (*env)->GetStringUTFChars(env, jstr, 0);*const char *str = env->GetStringUTFChars(jstr, 0);*/#include "Sample1.h"#include #include JNIEXPORT jint JNICALLJava_Sample1_intMethod(JNIEnv *env, jobject obj, jint num){return num * num;}JNIEXPORT jboolean JNICALLJava_Sample1_booleanMethod(JNIEnv *env, jobject obj, jboolean boolean){return !boolean;}JNIEXPORT jstring JNICALLJava_Sample1_stringMethod(JNIEnv *env, jobject obj, jstring jstr){const char *str = (*env)->GetStringUTFChars(env, jstr, 0);char cap[128];strcpy(cap, str);(*env)->ReleaseStringUTFChars(env, jstr, str);char* ptr = cap;while (*ptr != '\0'){*ptr = toupper(*ptr);ptr++;}return (*env)->NewStringUTF(env, cap);}JNIEXPORT jint JNICALLJava_Sample1_intArrayMethod(JNIEnv *env, jobject obj, jintArray array){int i, sum = 0;jsize len = (*env)->GetArrayLength(env, array);jint *body = (*env)->GetIntArrayElements(env, array, 0);for (i=0; iReleaseIntArrayElements(env, array, body, 0);return sum;}

C与C++的实现基本一样,唯一的差异在于用来访问 JNI 函数的方法。在 C 中,JNI 函数调用由“(*env)->”作前缀,目的是为了取出函数指针所引用的值。在 C++ 中,JNIEnv 类拥有处理函数指针查找的内联成员函数。下面将说明这个细微的差异,其中,这两行代码访问同一函数,但每种语言都有各自的语法。

C 语法:jsize len = (*env)->GetArrayLength(env,array);C++ 语法:jsize len = env->GetArrayLength(array);

编译命令

gcc -I /usr/lib/jvm/java-1.6.0-openjdk/include/ -I /usr/lib/jvm/java-1.6.0-openjdk/include/linux/ Sample1.c -fPIC -shared -o libSample1.so

运行结果与上面C++的输出是一致的。

实际上我是用了一个脚本完成编译等工作的

完成整个过程的脚本 (run.sh) download

#!/bin/bashecho "### compile Sample1.java"javac Sample1.javaecho "### generate jni headerfile Sample1.h"javah -classpath ./ -jni Sample1echo "### compile cpp Sample1.so"g++ -I /usr/lib/jvm/java-1.6.0-openjdk/include/ -I /usr/lib/jvm/java-1.6.0-openjdk/include/linux/ Sample1.cpp -fPIC -shared -o libSample1.soexportLD_LIBRARY_PATH=.:$LD_LIBRARY_PATHecho "### run cpp"echo "---------------"java Sample1echo "--------------- end"rm libSample1.soecho "### compile c Sample1.so"gcc -I /usr/lib/jvm/java-1.6.0-openjdk/include/ -I /usr/lib/jvm/java-1.6.0-openjdk/include/linux/ Sample1.c -fPIC -shared -o libSample1.soecho "### run c"echo "---------------"java Sample1#rm libSample1.so Sample1.class Sample1.h

脚本的运行结果如下图

bcfd324a982aab74875ded30420c0297.png

github上本文的例子代码 jni调用的例子

本文参考了以下两个blog的内容, 代码来自第二个blog。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值