【问题标题】:How do I access return value of a Java method returning java.lang.String from C++ in JNI?如何在 JNI 中访问从 C++ 中返回 java.lang.String 的 Java 方法的返回值?
【发布时间】:2010-08-03 14:30:16
【问题描述】:

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

我的代码如下:

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 代码

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

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

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

【问题讨论】:

    标签: java c++ java-native-interface


    【解决方案1】:

    你应该有

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

    那么你需要调用构造函数来获取一个新的对象:

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

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

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

    现在调用方法:

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

    【讨论】:

    • 类名应以 ; 结尾比如:()Ljava/lang/String;
    • 无法使用“jobject”类型的右值(又名“_jobject *”)初始化“jstring”类型的变量(又名“_jstring *”)jstring jMacAddr = env->CallObjectMethod(producDescription,
    • 只是对 jstring 的对象如下: rv = (jstring)(env->CallObjectMethod(classifierObj, getStringMethod, 0));
    【解决方案2】:

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

    Java 端

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

    原生端

    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);
    

    【讨论】:

      【解决方案3】:

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

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

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

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

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

      祝你好运

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-05-14
          • 2014-02-28
          • 2023-03-29
          • 2013-10-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-27
          相关资源
          最近更新 更多