我可以使用 JNI 函数调用将字符串从 Java 传递到我的 C++ 例程并在 C++ 例程中修改其值吗?
到目前为止,我已经看到了返回 jstring 的示例,但我不想这样做。我知道的另一个选项是获取 C++ 中字符串变量的 ID 并设置其值。
目前我正在玩的功能如下:
JNIEXPORT void JNICALL Java_myexample_ChangeString
(JNIEnv *, jobject obj, jstring strJava)
我想改变strJava的值。所以,本质上我要问的是 Java 是否可以通过引用而不只是通过值传递变量。
谢谢。
Java 字符串在设计上是不可变的,您无法更改它们,即使使用 JNI 也是如此。
所以,看来您真正想做的是从本机方法返回多个值。没有直接的方法可以做到这一点,但有一些间接的方法:
boolean
,而是创建一个包含 boolean
和 String
的类,并让本机代码创建并返回该类的实例。String[]
作为参数,并让本机代码将其字符串结果设置为该数组的第一个元素。#setStringValue(String)
方法创建一个类,并将其传递到本机方法中,然后该方法将调用该方法来提供字符串结果。一旦本机调用完成,创建帮助器类的 Java 代码就可以提取字符串值。在这些可能性中,单元素数组可能是最容易通过 JNI 代码处理的,因为它不涉及查找其他类或方法。但是,如果我想从非本机方法返回额外信息,我可能会返回包含这两个结果的新类的实例。
您不能直接修改
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!