一、 Java和JNI类型对照
1.1 基本类型对照表
Java类型 | Native类型 | C/C++类型 | 大小 |
---|---|---|---|
Boolean | jboolean | unsigned char | 无符号8位 |
Byte | jbyte | char | 有符号8位 |
Char | jchar | unsigned short | 无符号16位 |
Short | jshort | short | 有符号16位 |
Integer | jint | int | 有符号32位 |
Long | jlong | long long | 有符号64位 |
Float | jfloat | float | 32位浮点值 |
Double | jdouble | double | 64位双精度浮点值 |
1.2 引用类型对照表
Java类型 | Native类型 |
---|---|
java.lang.Class | jclass |
java.lang.Throwable | jthrowable |
java.lang.String | jstring |
java.lang.Object | jobject |
java.util.Objects | jobjects |
java.lang.Object[] | jobjectArray |
Boolean[] | jbooleanArray |
Byte[] | jbyteArray |
Char[] | jcharArray |
Short[] | jshortArray |
int[] | jintArray |
long[] | jlongArray |
float[] | jfloatArray |
double[] | jdoubleArray |
通用数组 | jarray |
说明任何Java数组在JNI里面都可以使用jarray 来表示,比如Java的int[] 数组,用JNI可以表示为jintArray ,也可以表示为jarray |
二、JNI函数详解
2.1 JNI函数的解析
首先我们需要在Java代码里面声明Native方法原型,比如:
public native void helloJNI(String msg);
其次我们需要在C/C++代码里面声明JNI方法原型,比如:
extern "C"
JNIEXPORT void JNICALL
Java_com_kgdwbb_jnistudy_MainActivity_helloJNI(JNIEnv* env, jobject thiz,jstring msg) {
//do something
}
JNI函数的原型
[extern “C”]JNIEXPORT 函数返回值 JNICALL 完整的函数声明(JNIENV *env, jobject thiz, …)
extern "C"
根据需要动态添加,如果是C++代码,则必须要添加extern “C”声明,如果是C代码,则不用添加。
JNIEXPORT
这个关键字说明这个函数是一个可导出函数,学过C/C++的朋友都知道,C/C++ 库里面的函数有些可以直接被外部调用,有些不可以,原因就是每一个C/C++库都有一个导出函数列表,只有在这个列表里面的函数才可以被外部直接调用,类似Java的public函数和private函数的区别。
JNICALL
说明这个函数是一个JNI函数,用来和普通的C/C++函数进行区别,实际发现不加这个关键字,Java也是可以调用这个JNI函数的。
Void
说明这个函数的返回值是void,如果需要返回值,则把这个关键字替换成要返回的类型即可。
Java_com_kgdwbb_jnistudy_MainActivity_helloJNI(JNIEnv*env, jobject thiz,jstring msg)
这是完整的JNI函数声明,JNI函数名的原型如下:
Java_ + JNI方法所在的完整的类名,把类名里面的”.”替换成”_” + 真实的JNI方法名,这个方法名要和Java代码里面声明的JNI方法名一样+ JNI函数必须的默认参数(JNIEnv* env, jobjectthiz)
env
参数是一个指向JNIEnv函数表的指针,thiz
参数代表的就是声明这个JNI方法的Java类的引用msg
参数就是和Java声明的JNI函数的msg参数对于的JNI函数参数
2.2 静态JNI方法和实例JNI方法区别
Java代码:
public native void showHello();
public native static void showHello2();
JNI代码:
extern "C"
JNIEXPORT void JNICALL
Java_com_kgdwbb_jnistudy_MainActivity_showHello(JNIEnv* env, jobject thiz) {
//do something
}
extern "C"
JNIEXPORT void JNICALL
Java_com_kgdwbb_jnistudy_MainActivity_showHello2(JNIEnv* env, jclass thiz) {
//do something
}
普通的JNI方法对应的JNI函数的第二个参数是jobject
类型,而静态的JNI方法对应的JNI函数的第二个参数是jclass
类型
三、JNI常用函数
3.1 JNI字符串相关的函数
C/C++字符串转JNI字符串
NewString
函数用来生成Unicode JNI字符串
NewStringUTF
函数用来生成UTF-8 JNI字符串
extern "C"
JNIEXPORT void JNICALL
Java_com_kgdwbb_jnistudy_MainActivity_testJString(JNIEnv* env, jobject thiz,jstring jstr) {
char *str="helloboy";
jstring jstr2=env->NewStringUTF(str);
const jchar *jchar2=env->GetStringChars(jstr,NULL);
size_t len=env->GetStringLength(jstr);
jstring jstr3=env->NewString(jchar2,len);
}
JNI字符串转C/C++字符串
GetStringChars
函数用来从jstring获取Unicode C/C++字符串
GetStringUTFChars
函数用来从jstring获取UTF-8 C/C++字符串
extern "C"
JNIEXPORT void JNICALL
Java_com_kgdwbb_jnistudy_MainActivity_testJString(JNIEnv* env, jobject thiz,jstring jstr) {
const char *str=env->GetStringUTFChars(jstr,NULL);
const jchar *jchar2=env->GetStringChars(jstr,NULL);
}
释放JNI字符串
ReleaseStringChars
函数用来释放Unicode C/C++字符串
ReleaseStringUTFChars
函数用来释放UTF-8 C/C++字符串
当你的本地代码使用完通过 GetStringUTFChars
获取的 UTF-8 字符串后,调用 ReleaseStringUTFChars
表明本地代码不再需要 GetStringUTFChars
返回的 UTF-8 字符串了,就能够释放掉 UTF-8 字符串占用的内存。不调用 ReleaseStringUTFChars
进行内存释放会导致内存泄漏,最终导致内存耗尽。
extern "C"
JNIEXPORT void JNICALL
Java_com_kgdwbb_jnistudy_MainActivity_testJString(JNIEnv* env, jobject thiz,jstring jstr) {
const char *str=env->GetStringUTFChars(jstr,NULL);
env->ReleaseStringUTFChars(jstr,str);
const jchar *jchar2=env->GetStringChars(jstr,NULL);
env->ReleaseStringChars(jstr,jchar2);
}
JNI字符串截取
GetStringRegion
函数用来截取Unicode JNI字符串
GetStringUTFRegion
函数用来截取UTF-8 JNI字符串
extern "C"
JNIEXPORT void JNICALL
Java_com_kgdwbb_jnistudy_MainActivity_testJString(JNIEnv* env, jobject thiz,jstring jstr) {
const char *str=env->GetStringUTFChars(jstr,NULL);
char *subStr=new char;
env->GetStringUTFRegion(jstr,0,3,subStr);
env->ReleaseStringUTFChars(jstr,str);
const jchar *jchar2=env->GetStringChars(jstr,NULL);
jchar *subJstr=new jchar;
env->GetStringRegion(jstr,0,3,subJstr);
env->ReleaseStringChars(jstr,jchar2);
}
获取JNI字符串的长度
GetStringLength
用来获取Unicode JNI字符串的长度
GetStringUTFLength
函数用来获取UTF-8 JNI字符串的长度
extern "C"
JNIEXPORT void JNICALL
Java_com_kgdwbb_jnistudy_MainActivity_testJString(JNIEnv* env, jobject thiz,jstring jstr) {
jsize len=env->GetStringLength(jstr);
jsize len2=env->GetStringUTFLength(jstr);
}
3.2 JNI数组相关的函数
JNI数组相关的类
Java类型 | Native类型 |
---|---|
java.lang.Object[] | jobjectArray |
Boolean[] | jbooleanArray |
Byte[] | jbyteArray |
Char[] | jcharArray |
Short[] | jshortArray |
int[] | jintArray |
long[] | jlongArray |
float[] | jfloatArray |
double[] | jdoubleArray |
通用数组 | jarray |
说明任何Java数组在JNI里面都可以使用jarray 来表示,比如Java的int[] 数组,用JNI可以表示为jintArray ,也可以表示为jarray |
获取JNI基本类型数组元素
Get< Type>ArrayElements
函数用来获取基本类型JNI数组的元素,这里面的< Type>需要被替换成实际的类型,比如GetIntArrayElements
,GetLongArrayElements
等
extern "C"
JNIEXPORT void JNICALL
Java_com_kgdwbb_jnistudy_MainActivity_testJIntArray(JNIEnv* env, jobject thiz,jintArray array) {
jint *intArray=env->GetIntArrayElements(array,NULL);
int len=env->GetArrayLength(array);
for(int i=0;i<len;i++){
jint item=intArray[i];
}
}
</