4

I write a jni function to set the value of two java Integer object in C, just like this:

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

In java, I called this function:

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

The output are both '10', why?

===============================================

I have done many tests, and got the following points. (Answer, comments are welcome)

  1. I don't think this jni native is unable to alter immutable object. After all, the both objects are changed to 10 from 0.

  2. There is some relation to auto-boxing (yes? I'm not sure). Maybe p1 and p2 are specially processed by jvm, made pointed to a single object if initialized with:

    Integer p1=0, p2=0;

If change to:

Integer p1=0, p2=1;

or

Integer p1 = new Integer(0);
Integer p2 = new Integer(0);

The result is right (p1:5, p2:10). Can anyone clarify this?

Maybe what I said is not correct. I have write the following code in java:

Integer a = 0;
Integer b = 0;
b = 10;
Log.d("test", "a: "+a);
Log.d("test", "b: "+b);

It output 0, 10. So, they point to not a single object. I'm really confused.

pengguang001
  • 4,045
  • 6
  • 27
  • 31
  • Don't attempt this. It will break Autoboxing and the caching of small Integer values. – user207421 May 19 '12 at 16:15
  • Re your edit you don't appear to have read my comment above. Don't do this. – user207421 May 22 '12 at 03:16
  • Thank you! Can you give me more explanation on autoboxing on this issue? If the two Integer objects are newed, my code works. But I don't if it's a good way to pass value like that. – pengguang001 May 22 '12 at 03:50
  • "Integer p1=0, p2=1;" will break too. See JLS 5.1.7 it says "If the value p being boxed is true, false, a byte, a char in the range \u0000 to \u007f, or an int or short number between -128 and 127, then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2." – Deucalion May 22 '12 at 05:05

2 Answers2

2
Integer i1 = 500, i2 = 10000;
testInts(i1, i2);
Log.d("log", "I1 = " + i1); 
Log.d("log", "I2 = " + i2);

or

Integer i1 = new Integer(0), i2 = new Integer(0);
testInts(i1, i2);
Log.d("log", "I1 = " + i1); 
Log.d("log", "I2 = " + i2);

output

I1 = 10
I2 = 10
I1 = 5
I2 = 10
I1 = 5
I2 = 10

Works (first result using your example). I have remembered something that if value is in byte (or?) range then java uses some weird optimization. EDIT: appears it is a rule for autoboxing for small values.

c code

    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;
Deucalion
  • 196
  • 1
  • 7
0

I don’t think Integer is mutable. You’ll see it has no set method.

Lawrence D'Oliveiro
  • 2,768
  • 1
  • 15
  • 13