You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Rust的jni crate获取Java字段并进行交互?

如何使用Rust的jni crate获取Java字段并进行交互?

嘿,刚好我之前用jni crate折腾过类似的场景,给你一步步拆解怎么实现哈!

首先得明确你的Java类结构,比如你有FirstClass,里面包含一个自定义类类型的字段,现在要在Rust的native方法里拿到这个自定义类的实例,然后和它交互。我先理清楚核心流程,再放完整的代码示例。

核心步骤梳理

  • 先拿到FirstClass的实例对象(就是native方法参数里的obj)
  • 获取FirstClass的类引用,这样才能找到它的字段信息
  • 根据字段名和正确的字段签名拿到字段ID,这一步很容易踩坑,签名格式千万不能错
  • 取出字段对应的自定义类实例对象
  • 接下来就可以对这个自定义类实例做各种操作:读它的字段、调用它的方法都没问题

完整代码示例

先给你看Java这边的类结构(方便对应Rust代码):

// FirstClass.java
package name.11nteresting.example;
public class FirstClass {
    // 我们要获取的目标字段
    private SecondClass mySecondClass;

    public FirstClass() {
        this.mySecondClass = new SecondClass();
    }

    // 声明native方法
    public native void example();
}

// SecondClass.java
package name.11nteresting.example;
public class SecondClass {
    public int someInt = 42;
    public String someString = "Hello from Java!";

    public void doSomething() {
        System.out.println("SecondClass's doSomething called!");
    }
}

然后是Rust这边的native方法实现:

use jni::{JNIEnv, JObject};

#[no_mangle]
pub extern "system" fn Java_name_11nteresting_example_FirstClass_example<'local>(
    mut env: JNIEnv<'local>,
    obj: JObject<'local>, // 这个就是FirstClass的实例对象
) {
    // 1. 获取FirstClass的类引用
    let first_class = match env.get_object_class(obj) {
        Ok(class) => class,
        Err(e) => {
            eprintln!("获取FirstClass类引用失败: {:?}", e);
            return;
        }
    };

    // 2. 获取mySecondClass字段的ID,注意签名格式:L完整包名/类名;
    let second_class_field_id = match env.get_field_id(
        first_class,
        "mySecondClass",
        "Lname/11nteresting/example/SecondClass;",
    ) {
        Ok(id) => id,
        Err(e) => {
            eprintln!("获取mySecondClass字段ID失败: {:?}", e);
            return;
        }
    };

    // 3. 取出FirstClass实例中的mySecondClass字段值(也就是SecondClass的实例)
    let second_class_obj: JObject<'local> = match env.get_field(obj, second_class_field_id) {
        Ok(field_value) => match field_value.l() {
            Ok(obj) => obj,
            Err(e) => {
                eprintln!("字段不是有效的对象类型: {:?}", e);
                return;
            }
        },
        Err(e) => {
            eprintln!("获取mySecondClass字段值失败: {:?}", e);
            return;
        }
    };

    // --- 现在可以和SecondClass实例交互了,举两个例子 ---

    // 例子1: 获取SecondClass的someInt字段值
    let second_class = match env.get_object_class(second_class_obj) {
        Ok(class) => class,
        Err(e) => {
            eprintln!("获取SecondClass类引用失败: {:?}", e);
            return;
        }
    };

    let some_int_field_id = match env.get_field_id(second_class, "someInt", "I") {
        Ok(id) => id,
        Err(e) => {
            eprintln!("获取someInt字段ID失败: {:?}", e);
            return;
        }
    };

    let some_int: i32 = match env.get_field(second_class_obj, some_int_field_id) {
        Ok(value) => match value.i() {
            Ok(int_val) => int_val,
            Err(e) => {
                eprintln!("someInt不是有效的int类型: {:?}", e);
                return;
            }
        },
        Err(e) => {
            eprintln!("获取someInt字段值失败: {:?}", e);
            return;
        }
    };
    println!("从SecondClass拿到的someInt值: {}", some_int);

    // 例子2: 调用SecondClass的doSomething方法
    let do_something_method_id = match env.get_method_id(second_class, "doSomething", "()V") {
        Ok(id) => id,
        Err(e) => {
            eprintln!("获取doSomething方法ID失败: {:?}", e);
            return;
        }
    };

    if let Err(e) = env.call_method(second_class_obj, do_something_method_id, &[]) {
        eprintln!("调用doSomething方法失败: {:?}", e);
    }
}

几个容易踩坑的点要注意:

  • 字段/方法签名必须准确:基本类型的签名比如int是I,boolean是Z,String是Ljava/lang/String;;自定义类的签名是L完整包名/类名;(注意末尾的分号不能丢)
  • 错误处理要到位:JNI操作很容易因为签名错、对象为空等失败,实际项目里别全用expect,用match或者?(如果函数返回Result的话)处理更稳妥
  • 函数命名规则:Rust里的native函数名要严格遵循JNI规范:Java_包名_类名_方法名,包名里的.要换成_,如果包名/类名有数字开头(比如你这里的11nteresting),要转成_1,确保和Java里的native方法完全对应
  • 生命周期:注意'local生命周期,确保所有JNI对象引用都在JNIEnv的生命周期内有效,避免悬垂引用

备注:内容来源于stack exchange,提问作者An1nterestingName

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 17:08:11