如何使用 Java 和 JNI 修改传递给 C++ 例程的 jstring 的值?

问题描述 投票:0回答:3

我可以使用 JNI 函数调用将字符串从 Java 传递到我的 C++ 例程并在 C++ 例程中修改其值吗?

到目前为止,我已经看到了返回 jstring 的示例,但我不想这样做。我知道的另一个选项是获取 C++ 中字符串变量的 ID 并设置其值。

目前我正在玩的功能如下:

JNIEXPORT void JNICALL Java_myexample_ChangeString
(JNIEnv *, jobject obj, jstring strJava) 

我想改变strJava的值。所以,本质上我要问的是 Java 是否可以通过引用而不只是通过值传递变量。

谢谢。

java java-native-interface
3个回答
6
投票

Java 字符串在设计上是不可变的,您无法更改它们,即使使用 JNI 也是如此。


3
投票

所以,看来您真正想做的是从本机方法返回多个值。没有直接的方法可以做到这一点,但有一些间接的方法:

  • 不要返回
    boolean
    ,而是创建一个包含
    boolean
    String
    的类,并让本机代码创建并返回该类的实例。
  • 传递一个单元素
    String[]
    作为参数,并让本机代码将其字符串结果设置为该数组的第一个元素。
  • 使用
    #setStringValue(String)
    方法创建一个类,并将其传递到本机方法中,然后该方法将调用该方法来提供字符串结果。一旦本机调用完成,创建帮助器类的 Java 代码就可以提取字符串值。

在这些可能性中,单元素数组可能是最容易通过 JNI 代码处理的,因为它不涉及查找其他类或方法。但是,如果我想从非本机方法返回额外信息,我可能会返回包含这两个结果的新类的实例。


0
投票

您不能直接修改

String
参数,因为 Java
String
是不可变的。然而,您可以做的是将字符串放入数组中,将数组传递给本机代码,然后在本机代码中(使用一些 JNI 互操作方法)创建一个新的 Java
String
并将数组中的引用替换为引用新字符串:

Caller.java:

package com.mycompany.myapp;

// Prototype for native method.
class MyJNI {
    public static native void changeStringsNative(String[] stringArr);
}

void CallNative()
{
    String[] myStringArr = new String[1] {"Original"};
    System.out.println("Original (Java): " + myStringArr[0]);
    MyJNI.changeStringsNative(myStringArr);
    System.out.println("Changed (Java): " + myStringArr[0]);
}

被叫者.c

#include <jni.h>
#include <stdio.h>

// Helper macro so we only need to declare class name once.
#define JNIFUNCTION(sig) Java_com_mycompany_myapp_MyJNI##sig

JNIEXPORT void JNICALL JNIFUNCTION(changeStringsNative(JNIEnv *env, jobject obj,
    jobjectArray myStringArr))
{
    int stringCount = env->GetArrayLength(myStringArr);
    for (int i = 0; i < stringCount; i++) {
        jstring myString = (jstring)(env->GetObjectArrayElement(myStringArr, i));
        const char *myStringOriginalC = env->GetStringUTFChars(myString, NULL);
        printtf("Original (native): %s\n", myStringOriginalC);
        env->ReleaseStringUTFChars(myString, myStringOriginalC);
        
        // Now do something in native to transform the string. For example, a printf involving the original.
        char *myStringChangedC = NULL;
        if (asprintf(&myStringChangedC, "Different from the %s!\n", myStringOriginalC) == -1) {
            // asprintf malloc error.
            return;
        }
        printtf("Changed (native): %s\n", myChangedStringC);

        // Create a new jstring and put into the array.
        env->SetObjectArrayElement(myStringArr, i, env->NewStringUTF(myChangedStringC));

        free(myStringChangedC); // must free after asprintf's malloc.
    }
    return true;
}

输出到标准输出:

Original (Java): Original
Original (native): Original
Changed (native): Different from the Original!
Changed (Java): Different from the Original!
© www.soinside.com 2019 - 2024. All rights reserved.