Jni如何傳遞而且修改兩個基礎參數

最近在開發jni時,須要返回多個參數給java。這個過程當中,碰到了一些問題,值得探討一下。java

 
具體是這樣,jni方法jni_do_something做了底層處理後,得出兩個int數據,須要將他們的值傳遞給java。在C語言中,直接用指針就能夠了。Java中能夠傳遞兩個Integer的引用。用JNI怎麼實現呢?
我在android frameworks源代碼中看了一下,對於相似傳值需求,android都是在java層自定義了一個class,用來封裝各個須要傳遞的參數。jni中須要修改時,得到該class的成員id,而後用SetIntField來修改。
 
我不想這麼作,由於相似的native方法比較多,我總不能每次都定義結構體吧,並且將不一樣方法的參數封裝在一個class中,也不太對,由於它們沒有共贊成義。
爲了讓jni能修改,Java層毫無疑問須要傳入Integer類型參數,這樣jni才認爲它是一個jobject,才能夠修改。好的,問題出現了。jni方法實現:
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;
}

java層調用若是這樣寫:android

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

這樣打印出的值是(10,10),而不是指望的(5,10)。爲何呢?ui

我在stackoverflow上發了一個貼,你們衆說紛紜。有的說跟mutable/imutable object有關,有的說跟autoboxing有關。
我再次作了試驗。若是寫成:
Integer p1=0, p2=1;
或者:
 
   
Integer p1 = new Integer(0);
Integer p2 = new Integer(0);
 
   
則打印的是預期結果。
 
原來,這跟autoboxing有關。當你用Integer p1 = 0這種方式時,java使用autoboxing機制將0封裝在一個Integer對象中,這時使用了Integer類的valueOf方法。在java 語言中,有一個很詭異的現象,對於在-128~127間的小數字,會在static pool中返回一個靜態對象,在這個範圍外的,會new一個Integer。
 
574:  Fun with auto boxing and the integer cache in Java
/**
 * Returns a <tt>Integer</tt> instance representing the specified
 * <tt>int</tt> value.
 * If a new <tt>Integer</tt> instance is not required, this method
 * should generally be used in preference to the constructor
 * {@link #Integer(int)}, as this method is likely to yield
 * significantly better space and time performance by caching
 * frequently requested values.
 *
 * @param  i an <code>int</code> value.
 * @return a <tt>Integer</tt> instance representing <tt>i</tt>.
 * @since  1.5
 */
public static Integer valueOf(int i) {
    if (i >= -128 && i <= IntegerCache.high)
        return IntegerCache.cache[i + 128];
    else
        return new Integer(i);
}

回到程序中來,若是寫成Integer p0 = 0, p1 = 0,它們是static pool中同一個對象的引用,所以jni中修改的是同一個對象。正確作法應該是使用new。this

相關文章
相關標籤/搜索