JNI学习

3 篇文章 0 订阅
1 篇文章 0 订阅

JNI数据类型

  1. JNI类型

    JNI意义
    JNIEnv*reference to JNI environment, which lets you access all the JNI fucntions
    jobjectreference to “this” Java object
  2. 基本数据类型(可直接在C语言中使用)

    JNIJava
    jintint
    jbytebyte
    jshortshort
    jlonglong
    jfloatfloat
    jdoubledouble
    jcharchar
    jbooleanboolean

    注意:jint对应的是C中的long

    // In "win\jni_mh.h" - machine header which is machine dependent
    typedef long            jint;
    typedef __int64         jlong;
    typedef signed char     jbyte;
    
    // In "jni.h"
    typedef unsigned char   jboolean;
    typedef unsigned short  jchar;
    typedef short           jshort;
    typedef float           jfloat;
    typedef double          jdouble;
    typedef jint            jsize;
    
  3. Java类型

    JNIJava
    jclassjava.lang.Class
    jstringjava.lang.String
    jthrowablejava.lang.Throwable
    jarray八大基本数据类型数组和jobjectArray

JNI函数

  1. jstring与char* 转换函数

    // UTF-8 String (encoded to 1-3 byte, backward compatible with 7-bit ASCII)
    // Can be mapped to null-terminated char-array C-string
    const char * GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);
       // Returns a pointer to an array of bytes representing the string in modified UTF-8 encoding.
    void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf);
       // Informs the VM that the native code no longer needs access to utf.
    jstring NewStringUTF(JNIEnv *env, const char *bytes);
       // Constructs a new java.lang.String object from an array of characters in modified UTF-8 encoding.
    jsize GetStringUTFLength(JNIEnv *env, jstring string);
       // Returns the length in bytes of the modified UTF-8 representation of a string.
    void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize length, char *buf);
       // Translates len number of Unicode characters beginning at offset start into modified UTF-8 encoding 
       // and place the result in the given buffer buf.
    
    // Unicode Strings (16-bit character)
    const jchar * GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy);
       // Returns a pointer to the array of Unicode characters
    void ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars);
       // Informs the VM that the native code no longer needs access to chars.
    jstring NewString(JNIEnv *env, const jchar *unicodeChars, jsize length);
       // Constructs a new java.lang.String object from an array of Unicode characters.
    jsize GetStringLength(JNIEnv *env, jstring string);
       // Returns the length (the count of Unicode characters) of a Java string.
    void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize length, jchar *buf);
       // Copies len number of Unicode characters beginning at offset start to the given buffer buf
    

    注意:GetStringCritical()ReleaseStringCritical()之间不能调用阻塞代码(IO操作或其他)。

  2. 基本数据类型数组转换函数

    // ArrayType: jintArray, jbyteArray, jshortArray, jlongArray, jfloatArray, jdoubleArray, jcharArray, jbooleanArray
    // PrimitiveType: int, byte, short, long, float, double, char, boolean
    // NativeType: jint, jbyte, jshort, jlong, jfloat, jdouble, jchar, jboolean
    NativeType * Get<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, jboolean *isCopy);
    void Release<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, NativeType *elems, jint mode);
    void Get<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize length, NativeType *buffer);
    void Set<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize length, const NativeType *buffer);
    ArrayType New<PrimitiveType>Array(JNIEnv *env, jsize length);
    void * GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy);
    void ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode);
    

    注意:Get|ReleasePrimitiveArrayCritical()之间不能调用阻塞代码(IO操作或其他)。

  3. jobject操作函数

    //根据jobject获取jclass
    jclass GetObjectClass(JNIEnv *env, jobject obj);
        // Returns the class of an object.
    
    //普通变量
    //步骤:获取jclass => 获取变量ID => 根据变量ID操作变量(Get/Set)
    jfieldID GetFieldID(JNIEnv *env, jclass cls, const char *name, const char *sig);
      // Returns the field ID for an instance variable of a class.
    
    NativeType Get<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID);
    void Set<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID, NativeType value);
      // Get/Set the value of an instance variable of an object
      // <type> includes each of the eight primitive types plus Object.
    
    //静态变量
    //步骤:获取jclass => 获取静态变量ID => 根据静态变量ID操作静态变量(Get/Set)
    jfieldID GetStaticFieldID(JNIEnv *env, jclass cls, const char *name, const char *sig);
      // Returns the field ID for a static variable of a class.
    
    NativeType GetStatic<type>Field(JNIEnv *env, jclass clazz, jfieldID fieldID);
    void SetStatic<type>Field(JNIEnv *env, jclass clazz, jfieldID fieldID, NativeType value);
      // Get/Set the value of a static variable of a class.
      // <type> includes each of the eight primitive types plus Object.
    
    //回调Java函数
    //步骤:获取jclass => 获取函数ID => 根据函数ID调用函数
    jmethodID GetMethodID(JNIEnv *env, jclass cls, const char *name, const char *sig);
       // Returns the method ID for an instance method of a class or interface.
    
    NativeType Call<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...);
    NativeType Call<type>MethodA(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
    NativeType Call<type>MethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
       // Invoke an instance method of the object.
       // The <type> includes each of the eight primitive and Object.
    
    jmethodID GetStaticMethodID(JNIEnv *env, jclass cls, const char *name, const char *sig);
       // Returns the method ID for an instance method of a class or interface.
    
    NativeType CallStatic<type>Method(JNIEnv *env, jclass clazz, jmethodID methodID, ...);
    NativeType CallStatic<type>MethodA(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
    NativeType CallStatic<type>MethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
       // Invoke an instance method of the object.
       // The <type> includes each of the eight primitive and Object.
    
    //调用重写方法
    //步骤:获取jclass => 获取函数ID => 根据函数ID调用函数
    NativeType CallNonvirtual<type>Method(JNIEnv *env, jobject obj, jclass cls, jmethodID methodID, ...);
    NativeType CallNonvirtual<type>MethodA(JNIEnv *env, jobject obj, jclass cls, jmethodID methodID, const jvalue *args);
    NativeType CallNonvirtual<type>MethodV(JNIEnv *env, jobject obj, jclass cls, jmethodID methodID, va_list args);
    

新建对象和对象数组

  1. 回调构造函数创建对象的函数

    //查找Java Class(Integer、Double等)
    jclass FindClass(JNIEnv *env, const char *name);
    
    //步骤:查找Class => 获取类构造函数ID => 新建对象
    jobject NewObject(JNIEnv *env, jclass cls, jmethodID methodID, ...);
    jobject NewObjectA(JNIEnv *env, jclass cls, jmethodID methodID, const jvalue *args);
    jobject NewObjectV(JNIEnv *env, jclass cls, jmethodID methodID, va_list args);
       // Constructs a new Java object. The method ID indicates which constructor method to invoke
    
    jobject AllocObject(JNIEnv *env, jclass cls);
      // Allocates a new Java object without invoking any of the constructors for the object.
    
  2. 构造对象数组的函数

    //步骤:查找Class => 根据类类型分配数组空间 => 调用构造函数构建类 => 将构建的单个类放入分配的数组
    jobjectArray NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement);
    // Constructs a new array holding objects in class elementClass.
    // All elements are initially set to initialElement.
    
    jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index);
       // Returns an element of an Object array.
    
    void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value);
       // Sets an element of an Object array.
    

局部和全局变量引用相关函数

//新建全局引用步骤:查找Class => 根据局部变量创建全局变量 => 释放局部变量
DeleteLocalRef()
DeleteGlobalRef()
NewGlobalRef()

参考:Java Programming Tutorial Java Native Interface (JNI)

JNI Tips

  1. 理论上,每个程序可以有多个JavaVM,但Android 只允许有一个
  2. 不可以在线程间共享JNIEnv(可以通过共享JavaVM并调用GetEnv来获取线程的JINEnv)
  3. 函数中每个参数的传入和几乎所有的返回都是局部引用
  4. 比较两个对象是否相同,只能调用isSameObject(),不能用==比较
  5. JNI的实现中,只有16个的局部引用,可以手动删除不需要的引用或通过EnsureLocalCapacity/PushLocalFrame来增加引用数量
  6. jfieldIdjmethodID不是对象引用,不应该传入NewGlobalRefGetSringUTFCharsGetByteArrayElements返回的也不是对象引用
  7. 在C中用pthread_create创建的线程,需要用AttachCurrentThreadAttachCurrentThreadAsDaemon附加到JNI,否则将无法调用JNI函数
  8. 如果调用了AttachCurrentThread来附加线程,局部引用将不会自动释放,直到线程分离。通常,在循环中的所有局部引用都需要手动释放
  9. Java使用的是UTF-16编码,而UTF-8编码更适合C调用string相关函数
  10. UTF-16 string没有zero-terminated,需要另外保存string的长度
  11. 不要忘记释放函数返回的jchar*jbyte*指针
  12. NewStringUTF需要传入UTF-8格式的字符串
  13. 使用JNI_COMMIT参数作释放操作,并不会释放空间,需要再次传入其他参数(0JNI_ABORT)释放。

参考:JNI Tips

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值