深入浅出C++ JNI类型系统
一、JNI类型系统概述
JNI(Java Native Interface)类型系统是连接Java和C++的桥梁,主要分为两大类:
1. 基本类型
- 对应Java的8种基本数据类型
- 命名规则:在Java类型前加
j(如jint对应int)
2. 引用类型
- 对应Java中的对象类型
- 包括类、对象、字符串、数组等
- 所有引用类型都继承自
jobject
二、基本类型对照表
| Java类型 | JNI类型 | C/C++类型 | 大小(位) |
|---|---|---|---|
| boolean | jboolean | unsigned char | 8 |
| byte | jbyte | signed char | 8 |
| char | jchar | unsigned short | 16 |
| short | jshort | short | 16 |
| int | jint | int | 32 |
| long | jlong | long long | 64 |
| float | jfloat | float | 32 |
| double | jdouble | double | 64 |
三、引用类型详解
1. 对象类型
jobject:所有Java对象的基类jclass:Java的Class对象(对应java.lang.Class)jstring:Java字符串对象(对应java.lang.String)jthrowable:异常对象(对应java.lang.Throwable)
2. 数组类型
jarray:所有数组的基类- 具体数组类型:
jbooleanArrayjbyteArrayjcharArrayjshortArrayjintArrayjlongArrayjfloatArrayjdoubleArrayjobjectArray
四、类型签名系统
JNI使用特定签名表示Java类型:
1. 基本类型签名
| Java类型 | 签名 |
|---|---|
| boolean | Z |
| byte | B |
| char | C |
| short | S |
| int | I |
| long | J |
| float | F |
| double | D |
| void | V |
2. 引用类型签名
- 类:
L全限定类名;(如Ljava/lang/String;) - 数组:
[类型签名(如[I表示int[]) - 方法:
(参数类型签名)返回值类型签名
五、类型转换实战技巧
1. 基本类型转换
// Java -> C++
jint javaInt = env->GetIntField(obj, fieldID);
int cppInt = (int)javaInt;
// C++ -> Java
jint javaInt = (jint)cppInt;
env->SetIntField(obj, fieldID, javaInt);
2. 字符串转换
// Java String -> C++字符串
const char* cppStr = env->GetStringUTFChars(javaStr, NULL);
// 使用后必须释放
env->ReleaseStringUTFChars(javaStr, cppStr);
// C++字符串 -> Java String
jstring javaStr = env->NewStringUTF(cppStr);
3. 数组转换
// Java数组 -> C++数组
jint* cppArray = env->GetIntArrayElements(javaArray, NULL);
jsize length = env->GetArrayLength(javaArray);
// 使用后必须释放
env->ReleaseIntArrayElements(javaArray, cppArray, 0);
// C++数组 -> Java数组
jintArray javaArray = env->NewIntArray(length);
env->SetIntArrayRegion(javaArray, 0, length, cppArray);
六、常见问题与陷阱
-
内存管理:
- JNI字符串和数组获取后必须释放
- 局部引用过多时需调用
DeleteLocalRef
-
类型混淆:
- 不要将
jint直接当作指针使用 - 注意
jlong在32位和64位平台的差异
- 不要将
-
异常处理:
- 检查
ExceptionOccurred避免崩溃 - 异常发生时先清除异常再返回
- 检查
-
线程安全:
- JNIEnv是线程相关的
- 多线程环境需要
AttachCurrentThread
七、最佳实践建议
-
类型检查:
- 使用
IsInstanceOf检查对象类型 - 数组操作前检查长度
- 使用
-
缓存常用类/方法ID:
- 在
JNI_OnLoad中缓存常用ID - 避免重复查找提升性能
- 在
-
使用CheckJNI:
- 开启CheckJNI检测常见错误
- 开发阶段特别有用
-
资源释放:
- 遵循谁申请谁释放原则
- 使用
RAII模式管理资源
理解JNI类型系统是编写健壮Native代码的基础,掌握这些知识可以避免大多数JNI开发中的常见错误。