android - r16 - ndk r13
Extraño: no se puede cambiar el valor de Integer en jni (2)
No creo que Integer sea mutable. Verás que no tiene un método set
.
Escribo una función jni para establecer el valor de dos objetos enteros java en C, así:
jni_do_something(JNIEnv *env, jobject thiz, jobject p1, jobject p2) {
jclass c;
jfieldID id;
c = env->FindClass("java/lang/Integer");
if (c==NULL)
{
LOGD("FindClass failed");
return -1;
}
id = env->GetFieldID(c, "value", "I");
if (id==NULL)
{
LOGD("GetFiledID failed");
return -1;
}
env->SetIntField(p1, id, 5);
env->SetIntField(p2, id, 10);
return 0;
}
En Java, llamé a esta función:
native int do_something(Integer p1, Integer p2);
Integer p1=0, p2=0;
do_something(p1, p2);
Log.d("test", "p1: "+p1);
Log.d("test", "p2: "+p2);
Los resultados son ambos ''10'', ¿por qué?
============================================
He hecho muchas pruebas y obtuve los siguientes puntos. (Respuesta, los comentarios son bienvenidos)
No creo que este jni nativo sea incapaz de alterar el objeto inmutable. Después de todo, los dos objetos se cambian a 10 desde 0.
Existe alguna relación con el auto-boxeo (¿sí? No estoy seguro). Tal vez p1 y p2 sean procesados especialmente por jvm, señalados a un solo objeto si se inicializan con:
Entero p1 = 0, p2 = 0;
Si cambias a:
Integer p1=0, p2=1;
o
Integer p1 = new Integer(0);
Integer p2 = new Integer(0);
El resultado es correcto (p1: 5, p2: 10). ¿Alguien puede aclarar esto?
Tal vez lo que dije no es correcto. He escrito el siguiente código en java:
Integer a = 0;
Integer b = 0;
b = 10;
Log.d("test", "a: "+a);
Log.d("test", "b: "+b);
Muestra 0, 10. Entonces, apuntan a que no hay un solo objeto. Estoy realmente confundido.
Integer i1 = 500, i2 = 10000;
testInts(i1, i2);
Log.d("log", "I1 = " + i1);
Log.d("log", "I2 = " + i2);
o
Integer i1 = new Integer(0), i2 = new Integer(0);
testInts(i1, i2);
Log.d("log", "I1 = " + i1);
Log.d("log", "I2 = " + i2);
salida
I1 = 10
I2 = 10
I1 = 5
I2 = 10
I1 = 5
I2 = 10
Funciona (primer resultado usando tu ejemplo). He recordado algo que dice que si el valor está en el rango de bytes (o?) Entonces Java usa una optimización extraña. EDITAR: aparece que es una regla para el autoboxing para valores pequeños.
código c
jclass clazz = (*env)->GetObjectClass(env, i1);
jfieldID mi = (*env)->GetFieldID(env, clazz, "value", "I");
(*env)->SetIntField(env, i1, mi, 5);
(*env)->SetIntField(env, i2, mi, 10);
return 0;