【问题标题】:How can I set the value of "Double" type variable of my Class by JNI?如何通过 JNI 设置我的 Class 的“Double”类型变量的值?
【发布时间】:2016-01-15 14:14:26
【问题描述】:

如果我只想将值设置为 Double 类型变量,我可以这样编写代码:

public static native int getDoubleVar(Double dobj);
JNIEXPORT jint JNICALL
test_jni_Native_testGet(JNIEnv *env, jclass type, jobject dobj)
{
    jclass DoubleClass = env->FindClass("java/lang/Double");
    jfieldID valueID = env->GetFieldID(DoubleClass, "value", "D");
    env->SetDoubleField(dobj, valueID, 2.3);
    return 0;
}

这些代码生效。

但是,当我尝试通过 JNI 设置一个类的“Double”变量的值时,我无法得到我想要的,当然,它崩溃了,这让我有点困惑。

Java 代码:

public class TestDouble
{

    public Double value;
    public long num;
    public TestDouble(long num, Double value)
    {
        this.num = num;
        this.value = value;
    }
}

本地人:

public static native int testGet(TestDouble tdobj);

c 代码:

JNIEXPORT jint JNICALL
test_jni_Native_testGet(JNIEnv *env, jclass type, jobject tdobj)
{
    jclass tdobjClass = env->FindClass("xxxx/TestDouble");
    jfieldID valueID = env->GetFieldID(tdobjClass, "value", "D");
    env->SetDoubleField(tdobj, jValueID, 2.3);
    return 0;
}

我想设置类'TestDouble'的'value'的值,'value'的类型是“Double”(不是double)。

E/dalvikvm: VM aborting
Fatal signal 6
Send stop signal to pid:5830 in void debuggerd_signal_handler(int, siginfo_t*, void*)

我这里只是粘贴了关键的错误词,很明显错误发生在:

env->SetDoubleField(tdobj, jValueID, 2.3);

那我该怎么做才能解决这个问题呢? 非常感谢!

【问题讨论】:

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


    【解决方案1】:

    我得到了正确答案:

    http://stackoverflow.com/questions/34848605/how-to-set-the-value-of-a-double-integer-type-of-a-java-class-by-jni
    
    JNIEXPORT jint JNICALL test_jni_Native_testSet(JNIEnv *env, jclass type, jobject tdobj)
    {
        //Create Integer class, get constructor and create Integer object
        jclass intClass = env->FindClass(env, "java/lang/Integer");
       jmethodID initInt = env->GetMethodID(env, intClass, "<init>", "(I)V");
        if (NULL == initInt) return -1;
        jobject newIntObj = env->NewObject(env, intClass, initInt, 123);
    
    //Now set your integer into value atttribute. For this, I would
    //recommend you to have a java setter and call it in the same way 
    //as shown above
    
    //clean reference
    env->DeleteLocalRef(env, newIntObj); 
    return 0;
    }
    

    Integer/Double 和其他包装类型可以用同样的方式处理..

    【讨论】:

      【解决方案2】:

      您的 C 代码假定 TestDouble.value 是原始 double 而不是对象 Double,因此在运行时失败。

      您可以将类定义更改为

      public class TestDouble
      {
          public double value;
          public long num;
          public TestDouble(long num, double value)
          {
              this.num = num;
              this.value = value;
          }
      }
      

      【讨论】:

      • 你的意思是我在一个类中只能使用double/int/float等基本类型而不是Double/Integer/Float..类型?
      • 有什么方法可以满足我在类中使用封装类型(Integer/Double/Float)并通过JNI设置值的目标吗?
      • @Hughie.Wang 当然你也可以使用 Doubles 或其他对象,但是你需要相应地调整你的 C 代码,例如调用env-&gt;GetFieldID(tdobjClass, "value", "Ljava/lang/Double;")获取Double字段的id...
      • 我按照你说的修改了代码,但是又崩溃了。并且一条新的错误消息显示“E/dalvikvm: JNI ERROR (app bug): attempt to use stale global reference 0x2”。
      【解决方案3】:

      如果您的 Double 对象已在 JAVA 代码中创建,则无需在 C++(对不起,不是 C)部分中创建新的 Double 对象。您可以执行以下操作:

      void setDoubleObjectField(JNIEnv* env, jobject PropertyDoubleObj, char* FieldName, double dValue)
      {
          jclass PropertyClass = (env)->GetObjectClass(PropertyDoubleObj);
      
          //printf("%s\n",getClassName( env, PropertyDoubleObj));
      
          jfieldID fidNumber = (env)->GetFieldID(PropertyClass, FieldName, "Ljava/lang/Double;");
          if (fidNumber == 0)
          {
      
              CreateException(env, std::string("Failed to query field from PropertyDouble class: ") + FieldName);
              return;
          }
      
          jobject DoubleObject = env->GetObjectField(PropertyDoubleObj, fidNumber);
      
          if (DoubleObject == 0) // That means, the object was simply not created. Just create one.
          {
              jclass DoubleClass = env->FindClass("java/lang/Double");
              jmethodID initDouble = env->GetMethodID( DoubleClass, "<init>", "(D)V");
              if (NULL == initDouble)
              {
                  CreateException(env, "Failed to create Double object.");
                  return;
      
              }
              DoubleObject = env->NewObject( DoubleClass, initDouble, dValue);
              env->SetObjectField(PropertyDoubleObj, fidNumber, DoubleObject);
              env->DeleteLocalRef(DoubleObject);
          }
          else
          {
              jclass DoubleCls = (env)->GetObjectClass(DoubleObject);
              jfieldID fidNumber_double = (env)->GetFieldID(DoubleCls, "value", "D");
              if (fidNumber_double == 0)
              {
                  CreateException(env, "Failed to query value field from Double class.");
                  return;
              }
      
              env->SetDoubleField(DoubleObject, fidNumber_double, dValue);
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 2022-07-13
        • 2016-11-05
        • 2020-01-14
        • 1970-01-01
        • 1970-01-01
        • 2022-11-28
        • 2018-03-19
        • 1970-01-01
        • 2022-01-15
        相关资源
        最近更新 更多