深入浅出C++ JNI类型系统

240 阅读2分钟

深入浅出C++ JNI类型系统

一、JNI类型系统概述

JNI(Java Native Interface)类型系统是连接Java和C++的桥梁,主要分为两大类:

1. 基本类型

  • 对应Java的8种基本数据类型
  • 命名规则:在Java类型前加j(如jint对应int

2. 引用类型

  • 对应Java中的对象类型
  • 包括类、对象、字符串、数组等
  • 所有引用类型都继承自jobject

二、基本类型对照表

Java类型JNI类型C/C++类型大小(位)
booleanjbooleanunsigned char8
bytejbytesigned char8
charjcharunsigned short16
shortjshortshort16
intjintint32
longjlonglong long64
floatjfloatfloat32
doublejdoubledouble64

三、引用类型详解

1. 对象类型

  • jobject:所有Java对象的基类
  • jclass:Java的Class对象(对应java.lang.Class
  • jstring:Java字符串对象(对应java.lang.String
  • jthrowable:异常对象(对应java.lang.Throwable

2. 数组类型

  • jarray:所有数组的基类
  • 具体数组类型:
    • jbooleanArray
    • jbyteArray
    • jcharArray
    • jshortArray
    • jintArray
    • jlongArray
    • jfloatArray
    • jdoubleArray
    • jobjectArray

四、类型签名系统

JNI使用特定签名表示Java类型:

1. 基本类型签名

Java类型签名
booleanZ
byteB
charC
shortS
intI
longJ
floatF
doubleD
voidV

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

六、常见问题与陷阱

  1. 内存管理

    • JNI字符串和数组获取后必须释放
    • 局部引用过多时需调用DeleteLocalRef
  2. 类型混淆

    • 不要将jint直接当作指针使用
    • 注意jlong在32位和64位平台的差异
  3. 异常处理

    • 检查ExceptionOccurred避免崩溃
    • 异常发生时先清除异常再返回
  4. 线程安全

    • JNIEnv是线程相关的
    • 多线程环境需要AttachCurrentThread

七、最佳实践建议

  1. 类型检查

    • 使用IsInstanceOf检查对象类型
    • 数组操作前检查长度
  2. 缓存常用类/方法ID

    • JNI_OnLoad中缓存常用ID
    • 避免重复查找提升性能
  3. 使用CheckJNI

    • 开启CheckJNI检测常见错误
    • 开发阶段特别有用
  4. 资源释放

    • 遵循谁申请谁释放原则
    • 使用RAII模式管理资源

理解JNI类型系统是编写健壮Native代码的基础,掌握这些知识可以避免大多数JNI开发中的常见错误。