如何通过 JNI 设置 Class 类型变量的 "Double" 值?
How can I set the value of "Double" type variable of my Class by JNI?
如果我只想将值设置为 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 设置 class 的 "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;
}
我想设置 class 'TestDouble' 的 'value' 的值, 'value' 的类型是 "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);
那我该怎么做才能解决这个问题呢?
非常感谢!
您的 C 代码假定 TestDouble.value
是原语 double
而不是对象 Double
,因此在运行时失败。
您可以将 class 定义更改为
public class TestDouble
{
public double value;
public long num;
public TestDouble(long num, double value)
{
this.num = num;
this.value = value;
}
}
我得到了正确答案:
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 和其他包装器类型可以用同样的方式处理..
如果您的 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);
}
}
如果我只想将值设置为 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 设置 class 的 "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;
}
我想设置 class 'TestDouble' 的 'value' 的值, 'value' 的类型是 "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);
那我该怎么做才能解决这个问题呢? 非常感谢!
您的 C 代码假定 TestDouble.value
是原语 double
而不是对象 Double
,因此在运行时失败。
您可以将 class 定义更改为
public class TestDouble
{
public double value;
public long num;
public TestDouble(long num, double value)
{
this.num = num;
this.value = value;
}
}
我得到了正确答案:
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 和其他包装器类型可以用同样的方式处理..
如果您的 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);
}
}