前言
本文承接 之前的
<a href="http://www.jianshu.com/p/476aae319808">jni简单数据</a>,采用String和数组的的类型传递和返回参数,以深入对于jni的了解
String 类型
修改 JniHello.java
/**
* Created by act64 on 2017/5/25.
*/
public class JniHello {
static{
System.loadLibrary("nativehello");
}
public static void main(String[]arg){
JniHello jniHello =new JniHello();
System.out.println( jniHello.hello("world"));
}
public native String hello(String str);
}
为了方便搞明白数据类型和参数以及对于的描述符,还是偷懒用javah生成
//在terminal里面输入
javac JniHello.java
javah JniHello
这样目录下就生成了JniHello.h文件
打开 JniHello.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JniHello */
#ifndef _Included_JniHello
#define _Included_JniHello
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: JniHello
* Method: hello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_JniHello_hello
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
我们在意的是Signature 和JNICALL Java_JniHello_hello的参数和返回值,将这些参数运用到我们上一篇简书写的hello.c中
#include <stdio.h>
#include <jni.h>
jstring c_hello(JNIEnv * env, jobject mJobject,jstring val){
const jbyte *str;
str = (*env)->GetStringUTFChars(env, val, NULL);
if (str == NULL) {
return NULL; /* OutOfMemoryError already thrown */
}
printf("java IN %s", str);
(*env)->ReleaseStringUTFChars(env, val, str);
return (*env)->NewStringUTF(env, "helloJNIStr");
}
const JNINativeMethod methods[]={
{"hello","(Ljava/lang/String;)Ljava/lang/String;",(jstring *)c_hello},
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNIEnv *env;
jclass cls;
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {
return JNI_ERR; /* JNI version not supported */
}
cls = (*env)->FindClass(env, "JniHello");
if (cls == NULL) {
return JNI_ERR;
}
if((*env)->RegisterNatives(env,cls,methods,1)<0){
return JNI_ERR;
}
return JNI_VERSION_1_4;
}
然后编译文件 ,命令在上一篇简书中有详细介绍,可以去翻一下 <a href="http://www.jianshu.com/p/476aae319808">jni简单数据</a>
gcc -fPIC -I /usr/lib/jvm/java-1.7.0-openjdk-amd64/include -shared -o libnativehello.so hello.c
export LD_LIBRARY_PATH=./
javac JniHello.java
java JniHello
结果如下
String输出.png数组
String就是这样传的,数组也是类似的,改写java文件和c文件
/**
* Created by act64 on 2017/5/25.
*/
public class JniHello {
static{
System.loadLibrary("nativehello");
}
public static void main(String[]arg){
JniHello jniHello =new JniHello();
int [] a={1,2,3};
int []b=jniHello.hello(a);
for (int i=0;i<3 ;i++ ) {
System.out.println( b[i]);
}
}
public native int[] hello(int[] ints);
}
hello.c
#include <stdio.h>
#include <jni.h>
#include <stdlib.h>
jintArray c_hello(JNIEnv * env, jobject mJobject,jintArray arr){
jint *carr;
jint i, sum = 0;
//将jintarray转为c++的int数组指针
carr = (*env)->GetIntArrayElements(env, arr, NULL);
if (carr == NULL) {
return 0; /* exception occurred */
}
//获得数组长度
jint length=(*env)->GetArrayLength(env,arr);
jint *buff;
//动态生成数组
//需要头文件stdlib
//并且malloc使用完后应该free
buff=malloc(length*sizeof(jint));
if (buff==NULL)
{
//使用完后,应该释放内存,下同
(*env)->ReleaseIntArrayElements(env, arr, carr, 0);
return 0;
/* code */
}
for (i=0; i<length; i++) {
sum += carr[i];
buff[i]=sum*sum;
}
//创建新的intarray
//用于返回给java
jintArray reArray=(*env)->NewIntArray(env,length);
//将c++数组的内容,拷贝到要返回给java的intarray去
(*env)->SetIntArrayRegion(env,reArray,0,length,buff);
(*env)->ReleaseIntArrayElements(env, arr, carr, 0);
printf("sum = %d\n", sum);
free(buff);
return reArray;
}
//描述符和返回类型
//利用javah命令可以看到
const JNINativeMethod methods[]={
{"hello","([I)[I",(jintArray *)c_hello},
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNIEnv *env;
jclass cls;
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {
return JNI_ERR; /* JNI version not supported */
}
cls = (*env)->FindClass(env, "JniHello");
if (cls == NULL) {
return JNI_ERR;
}
if((*env)->RegisterNatives(env,cls,methods,1)<0){
return JNI_ERR;
}
return JNI_VERSION_1_4;
}
然后运行编译命令。看输出
gcc -fPIC -I /usr/lib/jvm/java-1.7.0-openjdk-amd64/include -shared -o libnativehello.so hello.c
javac JniHello.java
java JniHello
输出如下
图片.png结语
本文主要讲了 jni中较为复杂的数据类型,字符串和数组的传递,下一篇将要讲一讲类对象的传递
网友评论