JNI数据类型
JNI类型
JNI 意义 JNIEnv* reference to JNI environment, which lets you access all the JNI fucntions jobject reference to “this” Java object 基本数据类型(可直接在C语言中使用)
JNI Java jint int jbyte byte jshort short jlong long jfloat float jdouble double jchar char jboolean boolean 注意: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;
Java类型
JNI Java jclass java.lang.Class jstring java.lang.String jthrowable java.lang.Throwable jarray 八大基本数据类型数组和jobjectArray
JNI函数
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操作或其他)。基本数据类型数组转换函数
// 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操作或其他)。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);
新建对象和对象数组
回调构造函数创建对象的函数
//查找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.
构造对象数组的函数
//步骤:查找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
- 理论上,每个程序可以有多个JavaVM,但Android 只允许有一个
- 不可以在线程间共享JNIEnv(可以通过共享JavaVM并调用GetEnv来获取线程的JINEnv)
- 函数中每个参数的传入和几乎所有的返回都是局部引用
- 比较两个对象是否相同,只能调用
isSameObject()
,不能用==
比较 - JNI的实现中,只有16个的局部引用,可以手动删除不需要的引用或通过
EnsureLocalCapacity
/PushLocalFrame
来增加引用数量 jfieldId
和jmethodID
不是对象引用,不应该传入NewGlobalRef
,GetSringUTFChars
和GetByteArrayElements
返回的也不是对象引用- 在C中用
pthread_create
创建的线程,需要用AttachCurrentThread
或AttachCurrentThreadAsDaemon
附加到JNI,否则将无法调用JNI函数 - 如果调用了
AttachCurrentThread
来附加线程,局部引用将不会自动释放,直到线程分离。通常,在循环中的所有局部引用都需要手动释放 - Java使用的是
UTF-16
编码,而UTF-8
编码更适合C调用string相关函数 UTF-16 string
没有zero-terminated
,需要另外保存string
的长度- 不要忘记释放函数返回的
jchar*
和jbyte*
指针 NewStringUTF
需要传入UTF-8
格式的字符串- 使用
JNI_COMMIT
参数作释放操作,并不会释放空间,需要再次传入其他参数(0
或JNI_ABORT
)释放。
参考:JNI Tips