`
todd_liu
  • 浏览: 66106 次
  • 性别: Icon_minigender_1
  • 来自: 江苏
社区版块
存档分类
最新评论

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);

分享到:
评论

相关推荐

    jni需要注意的常见问题

    ### jni需要注意的常见问题 #### 一、输入问题 在使用 JNI (Java Native Interface) 进行开发时,输入问题往往会被忽视但同样非常重要。尤其是当涉及到 C 或 C++ 的 `.c` 或 `.cpp` 文件时,由于不同平台间的编码...

    Jni 调用注意事项

    在使用JNI开发时,理解这些注意事项是至关重要的,能够帮助避免许多潜在的问题和错误,确保本地代码和Java代码之间的无缝交互。同时,使用JNI还涉及到线程安全、错误处理和性能优化等多个方面,这些都是开发者在实践...

    jni.zip jni编译jni下载

    在实际开发中,还需要注意一些细节,比如错误处理、内存管理(Java对象在本地代码中使用需要通过JNI函数创建和释放)、线程安全问题等。同时,由于涉及到跨语言和跨平台,理解JNI的工作原理和正确使用JNI头文件至关...

    使用JNI调用本地接口(解决中文字符传递,源码+说明)

    在DLL中,我们还需要注意线程安全问题。如果多个Java线程同时调用DLL中的函数,可能需要使用线程局部存储(TLS)或者其他同步机制来防止数据冲突。 在Java端,我们需要加载并初始化DLL。可以使用`System....

    DELPHI开发JNI必备 jni.pas

    此外,还要注意线程安全问题,因为Java是多线程的,而Delphi的代码可能需要同步控制以避免竞态条件。 总结来说,`jni.pas`和`JNI_MD.INC`是Delphi开发者使用JNI的关键组件,它们使得Delphi程序能够无缝地与Java世界...

    JNI传递中文字符串资料

    文档"JNI传递中文字符串.doc"和"jni的中文字符串处理.doc"将更深入地探讨这些主题,包括示例代码、最佳实践以及可能遇到的问题及解决方案。通过学习这些文档,开发者将能够熟练地在JNI环境中处理包含中文的字符串,...

    JAVA中jni使用

    JNI中的内存管理需要注意,因为Java和C/C++的内存模型不同。在本地代码中分配的内存需要在本地代码中释放,反之亦然。此外,JNI提供了引用计数机制,用于管理Java对象在本地代码中的生命周期。 7. **错误处理和...

    java中RCP中使用JNI

    - **线程安全**:Java是多线程的,而C/C++可能不支持,所以在JNI代码中要处理好线程同步问题。 - **异常处理**:JNI调用中出现错误时,可能需要通过抛出Java异常来通知Java层。 - **平台兼容性**:本地代码必须...

    安卓中实现jni读取内存信息

    要实现“安卓中实现JNI读取内存信息”,我们需要以下步骤: 1. **创建JNI头文件(.h)**:在Java源代码中,我们使用`native`关键字声明一个方法,比如`getMemoryInfo()`,然后使用`javah`工具生成对应的C++头文件。...

    jni操作list集合,来存储对象

    注意,由于Java对象不能直接在JNI中跨线程使用,因此如果要在C/C++中存储或操作Java对象,通常需要将对象序列化为基本类型(如整数或字符串)。对于复杂的对象,可能需要自定义序列化和反序列化逻辑。 5. **内存...

    使用JNI调用本地接口(解决中文问题)

    用 JNI 调用本地接口 作 者 : nxy1027@163.com在本文中,我们将深入探讨如何使用JNI(Java Native Interface)来调用本地接口,特别是在处理中文字符串时遇到的挑战。JNI是Java平台提供的一种机制,允许Java代码与...

    在JNI中得到手机IMEI号

    ### 在JNI中获取Android设备IMEI号的方法 #### 背景介绍 在移动应用开发过程中,有时我们需要获取Android设备的一些基本信息,例如IMEI(International Mobile Equipment Identity)号,这是一串由15位数字组成的...

    JniCallback.zip_Android jni_android_jni android_jni callback_jni

    在Android开发中,JNI(Java Native Interface)是一个关键的技术,它允许Java代码和其他语言写的代码进行交互。JNI在很多场景下都非常有用,比如优化性能、使用现有的C/C++库、或者像在这个“JniCallback.zip”文件...

    JNI的两个头文件jni.h和jni_md.h

    值得注意的是,JNI虽然强大,但也有其局限性和潜在的问题。例如,由于涉及到本地代码,调试起来可能较为复杂,且本地方法不享受Java的垃圾收集机制,需要手动管理内存。此外,过度使用JNI可能导致代码可移植性降低。...

    Android 5.0jni调用

    6. **线程安全**:在Android 5.0中,JNI函数默认运行在主线程之外,开发者需要注意多线程环境下的同步问题。正确地管理和同步本地资源,避免数据竞争,是保证应用稳定的关键。 7. **错误处理**:Android 5.0提供了...

    JNI实现回调及JNI开启线程

    在实际应用中,需要注意线程安全问题,特别是当JNI线程需要访问Java对象时。因为Java对象在不同线程间通常是不可直接共享的,需要进行适当的同步操作,如使用`MonitorEnter`和`MonitorExit`。此外,由于Java虚拟机会...

    Android调用Jni返回自定义对象

    这个过程中有几个需要注意的点: 1. 错误处理:JNI操作可能会抛出异常,如找不到类或方法,需要进行适当的错误处理。 2. 内存管理:由于C++和Java的内存管理机制不同,需要谨慎处理字符串和对象的生命周期,避免内存...

    Jni应用个人详解

    Jni应用详解 Jni(Java Native Interface)是一种allowing Java代码与 native 代码集成的技术,使得Java程序能够调用native方法和库。下面是Jni应用的详细解释...然而,Jni也存在一些常见问题,需要开发者注意和解决。

    Android中JNI实现AES加密源代码

    - **性能优化**:由于JNI调用比Java原生调用慢,因此应尽量减少不必要的跨语言调用,例如可以考虑一次性加密大量数据而不是单个字节。 综上所述,"Android中JNI实现AES加密源代码"涉及的知识点包括Android JNI的...

    JNI

    JNI在很多场景下都是必要的,比如当Java需要调用已有的C/C++库,或者想要利用硬件特性,或者优化性能时。这篇文章将深入探讨JNI的核心概念、使用方法以及在实际开发中的应用。 首先,JNI提供了Java虚拟机(JVM)与...

Global site tag (gtag.js) - Google Analytics