jni 中要注意的问题

JNI 的类型和数据结构
Java 类型  本地类型  说明
boolean  jboolean  无符号,8 位
byte     jbyte  无符号,8 位
char     jchar  无符号,16 位
short    jshort  有符号,16 位
int      jint  有符号,32 位
long     jlong  有符号,64 位
float    jfloat  32 位
double    jdouble  64 位
void     void  N/A
由于JVM中,使用统一的UTF-8编码,java传入的String参数,在c文件中被jni转换为jstring的数据类型,在c文件中声明char* psz,然后psz = (char*)(*env)->GetStringUTFChars(env, jstring, NULL);c++的操作简单些,env->GetStringUTFChars( jstring, NULL);注意使用完后,运行(*env)->ReleaseStringUTFChars(env, jstring, psz);
将一个c的字符串转为jstring,
static char lastfile[80];

  JNIEXPORT jstring JNICALL Java_ReadFile_lastFile
    (JNIEnv *env, jobject jobj) {
     return((*env)->NewStringUTF(env, lastfile));
  }
例子
JNIEXPORT jstring JNICALL
Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{
char buf[128];
const jbyte *str;
str = (*env)->GetStringUTFChars(env, prompt, NULL);
if (str == NULL) {
return NULL; /* OutOfMemoryError already thrown */
}
printf("%s", str);
(*env)->ReleaseStringUTFChars(env, prompt, str);
/* We assume here that the user does not type more than
* 127 characters */
scanf("%s", buf);
return (*env)->NewStringUTF(env, buf);
}
如果使用Unicode编码,不需要使用UTF-8处理,使用如下方法
JNIEXPORT jbyteArray JNICALL Java_ReadFile_loadFile
    (JNIEnv * env, jobject jobj, jstring name) {
      caddr_t m;
      jbyteArray jb;
      struct stat finfo;
      jboolean iscopy;
      const jchar *mfile = (*env)->GetStringChars(env,
  name, &iscopy);
  //...
      (*env)->ReleaseStringChars(env, name, mfile);
传递Array
boolean

 public static void setArray( boolean[] ba )
  {
    for( int i=0; i < ba.length; i++ )
      ba[i] = true;
    setArray0( ba );
  }

  private static native void setArray0( boolean[] ba );

布尔型数组被初始化为 true,本地方法将把特定的元素设置为 false。同时,在 Java 源代码中,我们可以更改 main 以使其包含测试代码:

    boolean[] ba = new boolean[5];
    MyNative.setArray( ba );
    for( int i=0; i < ba.length; i++ )
      System.out.println( ba[i] );

在编译源代码并执行 javah 以后,MyNative.h 头文件包含以下的原型:

/*
 * Class:     MyNative
 * Method:    setArray0
 * Signature: ([Z)V
 */
JNIEXPORT void JNICALL Java_MyNative_setArray0
  (JNIEnv *, jclass, jbooleanArray);

布尔型数组是作为单个名为 jbooleanArray 的类型创建的。
基本类型有它们自已的数组类型,如 jintArray 和 jcharArray。
非基本类型的数组使用 jobjectArray 类型。下一个示例中包括一个 jobjectArray。这个布尔数组的数组元素是通过 JNI 方法 GetBooleanArrayElements 来访问的。
针对每种基本类型都有等价的方法。这个本地方法是如下实现的:

JNIEXPORT void JNICALL Java_MyNative_setArray0
  (JNIEnv *env, jclass cls, jbooleanArray ba)
{
  jboolean* pba = (*env)->GetBooleanArrayElements( env, ba, 0 );
  jsize len = (*env)->GetArrayLength(env, ba);
  int i=0;
  // 更改偶数数组元素
  for( i=0; i < len; i+=2 )
    pba[i] = JNI_FALSE;
  (*env)->ReleaseBooleanArrayElements( env, ba, pba, 0 );
}

指向布尔型数组的指针可以使用 GetBooleanArrayElements 获得。
数组大小可以用 GetArrayLength 方法获得。使用 ReleaseBooleanArrayElements 方法释放数组。就可以读取和修改数组元素的值了。
int 数组

class IntArray {
    private native int sumArray(int[] arr);
    public static void main(String[] args) {
        IntArray p = new IntArray();
        int arr[] = new int[10];
        for (int i = 0; i < 10; i++) {
            arr[i] = i;
        }
        int sum = p.sumArray(arr);
        System.out.println("sum = " + sum);
    }

    static {
        System.loadLibrary("jnistudy");
    }
}

jni的c程序

#include <jni.h>
#include <stdio.h>
#include "IntArray.h"

JNIEXPORT jint JNICALL
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{
    jint *carr;
    jint i, sum = 0;
    carr = (*env)->GetIntArrayElements(env, arr, NULL);
    if (carr == NULL) {
        return 0; /* exception occurred */
    }

    for (i=0; i<10; i++) {
        sum += carr[i];
    }

    (*env)->ReleaseIntArrayElements(env, arr, carr, 0);
    return sum;
}

GetIntArrayRegion得到数组,ReleaseIntArrayElements释放资源,GetArrayLength得到数组的长度,SetIntArrayRegion修改数组元素的值。

多位int 数组

class ObjectArrayTest {
    private static native int[][] initInt2DArray(int size);
    public static void main(String[] args) {
        int[][] i2arr = initInt2DArray(3);
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                 System.out.print(" " + i2arr[i][j]);
            }
            System.out.println();
        }
    }
    static {
        System.loadLibrary("jnistudy");
    }
}

jni的代码
#include <jni.h>
#include <stdio.h>
#include "ObjectArrayTest.h"

JNIEXPORT jobjectArray JNICALL
Java_ObjectArrayTest_initInt2DArray(JNIEnv *env,
                                   jclass cls,
                                   jint size)
{
    jobjectArray result;
    int i;
    jclass intArrCls = (*env)->FindClass(env, "[I");
    if (intArrCls == NULL) {
        return NULL; /* exception thrown */
    }
    result = (*env)->NewObjectArray(env, size, intArrCls, NULL);
    if (result == NULL) {
        return NULL; /* out of memory error thrown */
    }
    for (i = 0; i < size; i++) {
        jint tmp[256];  /* make sure it is large enough! */
        int j;
        jintArray iarr = (*env)->NewIntArray(env, size);
        if (iarr == NULL) {
            return NULL; /* out of memory error thrown */
        }
        for (j = 0; j < size; j++) {
            tmp[j] = i + j;
        }
        (*env)->SetIntArrayRegion(env, iarr, 0, size, tmp);
        (*env)->SetObjectArrayElement(env, result, i, iarr);
        (*env)->DeleteLocalRef(env, iarr);
    }
    return result;
}
Get/SetObjectArrayElement得到和设置数组的元素的值。
传递 Java String 数组

本例将通过最常用的非基本类型,Java String,说明如何访问非基本对象的数组。字符串数组被传递给本地方法,而本地方法只是将它们显示到控制台上。
MyNative 类定义中添加了以下几个方法:

  public static void showStrings( String[] sa )
  {
    showStrings0( sa );
  }
  private static void showStrings0( String[] sa );

测试
  String[] sa = new String[] { "Hello,", "world!", "JNI", "is", "fun." };
  MyNative.showStrings( sa );

c代码中,本地方法分别访问每个元素,

JNIEXPORT void JNICALL Java_MyNative_showStrings0
  (JNIEnv *env, jclass cls, jobjectArray sa)
{
  int len = (*env)->GetArrayLength( env, sa );
  int i=0;
  for( i=0; i < len; i++ )
  {
    jobject obj = (*env)->GetObjectArrayElement(env, sa, i);
    jstring str = (jstring)obj;
    const char* szStr = (*env)->GetStringUTFChars( env, str, 0 );
    printf( "%s ", szStr );
    (*env)->ReleaseStringUTFChars( env, str, szStr );
  }
  printf( "\n" );
}

数组元素可以通过 GetObjectArrayElement 访问。 因为返回值是 jstring 类型,所以可以安全地将它从 jobject 类型转换为 jstring 类型。

返回 Java String 数组
在本地代码中创建一个字符串数组并将它返回给 Java 调用者。MyNative.java 中添加了以下几个方法:

  public static String[] getStrings()
  {
    return getStrings0();
  }
  private static native String[] getStrings0();

使用showStrings 将 getStrings 的输出显示出来:

  MyNative.showStrings( MyNative.getStrings() );

实现的本地方法返回五个字符串。

JNIEXPORT jobjectArray JNICALL Java_MyNative_getStrings0
  (JNIEnv *env, jclass cls)
{
  jstring      str;
  jobjectArray args = 0;
  jsize        len = 5;
  char*        sa[] = { "Hello,", "world!", "JNI", "is", "fun" };
  int          i=0;
  args = (*env)->NewObjectArray(env, len, (*env)->FindClass(env, "java/lang/String"), 0);
  for( i=0; i < len; i++ )
  {
    str = (*env)->NewStringUTF( env, sa[i] );
    (*env)->SetObjectArrayElement(env, args, i, str);
  }
  return args;
}

字符串数组是通过调用 NewObjectArray 创建的,同时传递了 String 类和数组长度两个参数。Java String 是使用 NewStringUTF 创建的。String 元素是使用 SetObjectArrayElement 存入数组中的。


另外要通过jni来改变java的参数引用,例如有参数jbyteArray account,修改完account的值后,java要获取该值,直接使用
jbyte* jbAccount = (env)->GetByteArrayElements(env, account, 0);
 char* szAccount = (char*)jbAccount;
指针的地址并不是account的地址,最后赋下值才行
env->SetByteArrayRegion(account,0,strlen(szAccount),jbyte* jbAccount);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值