JNIEnv *env 和 jobject obj
JNIEnv *env 和 jobject obj 是JNI函数中的两个重要参数,它们各自有不同的作用:
JNIEnv *env 参数
作用
JNIEnv 是JNI环境指针,提供了访问JVM功能的接口。
主要功能
-
调用Java方法:
Call<type>Method系列函数调用“Java实例”的方法CallStatic<type>Method系列函数调用Java静态方法
-
操作Java对象:
- 创建Java对象实例
- 获取Java对象的类
-
异常处理:
- 抛出Java异常
- 检查和处理JNI异常
-
字符串操作:
- Java字符串和C字符串之间的转换
NewStringUTF、GetStringUTFChars等
-
类型转换:
- 各种JNI类型之间的转换操作 以上都是通过访问JVM功能的接口来实现的。
示例用法
// 获取Java对象的类
jclass clazz = env->GetObjectClass(obj);
// 访问Java字段
jfieldID fieldId = env->GetFieldID(clazz, "fieldName", "I");
// 获取字段值
jint value = env->GetIntField(obj, fieldId);
jobject obj 参数
作用
代表调用该native方法的Java对象实例。
主要功能
-
访问调用对象:
- 可以访问调用native方法的那个Java对象
- 获取和修改该对象的字段
-
调用对象方法:
- 调用该对象的其他Java方法
-
对象状态管理:
- 维护与特定Java对象实例关联的状态
示例用法
// 获取对象的类
jclass clazz = env->GetObjectClass(obj);
// 获取对象字段
jfieldID fieldId = env->GetFieldID(clazz, "result", "I");
jint fieldValue = env->GetIntField(obj, fieldId);
// 修改对象字段
env->SetIntField(obj, fieldId, newValue);
Java代码示例
// CalculatorWithField.java
public class CalculatorWithField {
// 实例字段,用于存储计算结果
private int lastResult = 0;
// 静态字段,用于统计计算次数
private static int calculationCount = 0;
static {
System.loadLibrary("calculator_field");
}
// 声明native方法
public native int addWithField(int a, int b);
public native int getCalculationCount();
// 获取最后结果的Java方法
public int getLastResult() {
return lastResult;
}
public static void main(String[] args) {
CalculatorWithField calc = new CalculatorWithField();
System.out.println("初始lastResult: " + calc.getLastResult());
System.out.println("初始calculationCount: " + calc.getCalculationCount());
int result1 = calc.addWithField(10, 5);
System.out.println("10 + 5 = " + result1);
System.out.println("调用后lastResult: " + calc.getLastResult());
System.out.println("调用后calculationCount: " + calc.getCalculationCount());
int result2 = calc.addWithField(20, 30);
System.out.println("20 + 30 = " + result2);
System.out.println("再次调用后lastResult: " + calc.getLastResult());
System.out.println("再次调用后calculationCount: " + calc.getCalculationCount());
}
}
对应的JNI实现
// CalculatorWithFieldJNI.cpp
#include "CalculatorWithField.h"
#include <iostream>
JNIEXPORT jint JNICALL Java_CalculatorWithField_addWithField
(JNIEnv *env, jobject obj, jint a, jint b) {
// 1. 执行计算
int result = a + b;
std::cout << "执行加法: " << a << " + " << b << " = " << result << std::endl;
// 2. 使用env和obj访问Java对象的字段
// 获取对象的类
jclass clazz = env->GetObjectClass(obj);
// 获取实例字段ID
jfieldID lastResultFieldID = env->GetFieldID(clazz, "lastResult", "I");
// 设置实例字段值
env->SetIntField(obj, lastResultFieldID, result);
// 3. 访问和更新静态字段
jfieldID countFieldID = env->GetStaticFieldID(clazz, "calculationCount", "I");
jint currentCount = env->GetStaticIntField(clazz, countFieldID);
env->SetStaticIntField(clazz, countFieldID, currentCount + 1);
return result;
}
JNIEXPORT jint JNICALL Java_CalculatorWithField_getCalculationCount
(JNIEnv *env, jobject obj) {
// 获取对象的类
jclass clazz = env->GetObjectClass(obj);
// 获取静态字段值
jfieldID countFieldID = env->GetStaticFieldID(clazz, "calculationCount", "I");
return env->GetStaticIntField(clazz, countFieldID);
}
关键点说明
1. 访问实例字段
// 获取对象类
jclass clazz = env->GetObjectClass(obj);
// 获取字段ID
jfieldID lastResultFieldID = env->GetFieldID(clazz, "lastResult", "I");
// 设置字段值
env->SetIntField(obj, lastResultFieldID, result);
2. 访问静态字段
// 获取静态字段ID
jfieldID countFieldID = env->GetStaticFieldID(clazz, "calculationCount", "I");
// 获取和设置静态字段值
jint currentCount = env->GetStaticIntField(clazz, countFieldID);
env->SetStaticIntField(clazz, countFieldID, currentCount + 1);
3. 调用Java方法示例
// 如果需要调用Java方法
jmethodID methodID = env->GetMethodID(clazz, "getLastResult", "()I");
jint result = env->CallIntMethod(obj, methodID);
预期输出
初始lastResult: 0
初始calculationCount: 0
执行加法: 10 + 5 = 15
调用后lastResult: 15
调用后calculationCount: 1
执行加法: 20 + 30 = 50
再次调用后lastResult: 50
再次调用后calculationCount: 2