如何访问从 JNI 中的 C++ 返回 java.lang.String 的 Java 方法的返回值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3397513/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 01:39:11  来源:igfitidea点击:

How do I access return value of a Java method returning java.lang.String from C++ in JNI?

javac++java-native-interface

提问by Juan Macek

I am trying to pass back a string from a Java method called from C++. I am not able to find out what JNI function should I call to access the method and be returned a jstring value.

我试图从 C++ 调用的 Java 方法传回一个字符串。我无法找出应该调用什么 JNI 函数来访问该方法并返回一个 jstring 值。

My code follows:

我的代码如下:

C++ part

C++部分

main() {
    jclass cls;
    jmethodID mid;
    jstring rv;

/** ... omitted code ... */

    cls = env->FindClass("ClassifierWrapper");
    mid = env->GetMethodID(cls, "getString","()Ljava/lang/String");

    rv = env->CallStatic<TYPE>Method(cls, mid, 0);
    const char *strReturn = env->GetStringUTFChars(env, rv, 0);

    env->ReleaseStringUTFChars(rv, strReturn);
}

Java Code

Java代码

public class ClassifierWrapper {
    public String getString() { return "TEST";}
}

The Method Signature(from "javap -s Class")

方法签名(来自“javap -s Class”)

public java.lang.String getString();
  Signature: ()Ljava/lang/String;

回答by Marimuthu Madasamy

You should have

你应该有

cls = env->FindClass("ClassifierWrapper"); 

Then you need to invoke the constructor to get a new object:

然后你需要调用构造函数来获取一个新对象:

jmethodID classifierConstructor = env->GetMethodID(cls,"<init>", "()V"); 
if (classifierConstructor == NULL) {
  return NULL; /* exception thrown */
}

jobject classifierObj = env->NewObject( cls, classifierConstructor);

You are getting static method (even though the method name is wrong). But you need to get the instance method since getString() is not static.

您正在获取静态方法(即使方法名称错误)。但是您需要获取实例方法,因为 getString() 不是静态的。

jmethodID getStringMethod = env->GetMethodID(cls, "getString", "()Ljava/lang/String;"); 

Now invoke the method:

现在调用方法:

rv = env->CallObjectMethod(classifierObj, getStringMethod, 0); 
const char *strReturn = env->GetStringUTFChars(env, rv, 0);

回答by cahit beyaz

The complete working solution is as below:

完整的工作解决方案如下:

Java Side

Java端

public class ClassifierWrapper {
public ClassifierWrapper(){}
public String getString() { return "TEST";}
}

Native Side

本机端

jclass cls;
jmethodID mid;
jstring rv;


cls = jniEnv->FindClass("ClassifierWrapper"); //plase also consider your package name as package\name\classname

jmethodID classifierConstructor = jniEnv->GetMethodID(cls,"<init>", "()V");
if (classifierConstructor == NULL) {
    return NULL; /* exception thrown */
}
jobject classifierObj = jniEnv->NewObject( cls, classifierConstructor);

jmethodID getStringMethod = jniEnv->GetMethodID(cls, "getString", "()Ljava/lang/String;");

rv = (jstring)(jniEnv->CallObjectMethod(classifierObj, getStringMethod));
const char *strReturn = jniEnv->GetStringUTFChars( rv, 0);


jniEnv->ReleaseStringUTFChars(rv, strReturn);

回答by aweisberg

The first problem is that ClassifierWrapper.getString() is not static. You will need to make it static or instantiate ClassifierWrapper.

第一个问题是 ClassifierWrapper.getString() 不是静态的。您需要将其设为静态或实例化 ClassifierWrapper。

The second problem is that you are using GetMethodId instead of GetStaticMethodId.

第二个问题是您使用的是 GetMethodId 而不是 GetStaticMethodId。

To invoke a method that returns an Object (such as a String) you would call CallStaticObjectMethod(). That will return a jobject local reference to the String that the method returned. You can safely cast the jobject to a jstring (see http://java.sun.com/docs/books/jni/html/types.html) and use GetStringUTFChars to retrieve the characters and GetStringUTFLength to get the number of characters.

要调用返回对象(例如字符串)的方法,您将调用 CallStaticObjectMethod()。这将返回对方法返回的字符串的作业本地引用。您可以安全地将 jobject 转换为 jstring(请参阅http://java.sun.com/docs/books/jni/html/types.html)并使用 GetStringUTFChars 来检索字符并使用 GetStringUTFLength 来获取字符数。

JNI is very tricky. You need to check the error code for everything (use ExceptionCheck() when there is no error code). If you don't check for errors it will fail silently in most cases and usually not at the point where the actual bug is.

JNI 非常棘手。您需要检查所有内容的错误代码(当没有错误代码时使用 ExceptionCheck())。如果您不检查错误,它会在大多数情况下静默失败,并且通常不会出现在实际错误所在的位置。

You also need to understand the difference between local and global references (and what methods generate new references) in order to not leak memory and run into the reference limit. For instance, FindClass returns a local reference to a class object, but GetMethodId returns a MethodID.

您还需要了解局部引用和全局引用之间的区别(以及哪些方法会生成新引用),以免内存泄漏并遇到引用限制。例如,FindClass 返回对类对象的本地引用,而 GetMethodId 返回 MethodID。

Good luck

祝你好运

回答by Carlos Pineda

The signature ()Ljava/lang/Stringis wrong, due that a class name into JVM must terminate with ;, then in this case signature must be ()Ljava/lang/String;

签名()Ljava/lang/String是错误的,因为进入JVM的类名必须以 终止;,那么在这种情况下签名必须是()Ljava/lang/String;