zoukankan      html  css  js  c++  java
  • Jni如何传递并且修改两个基础参数

    最近在开发jni时,需要返回多个参数给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层调用如果这样写:

    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)。为什么呢?

    我在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。

  • 相关阅读:
    bootstrap-datetimepicker日期控件下载
    【eclipse】启动不了报错java was started but returned exit code=13
    jsp选项卡导航实现——模板
    【eclipse】Multiple annotations found at this line:——解决方法
    【链接】SpringBoot启动错误
    eclipse隐藏关闭的工程
    【链接】虚拟机使用桥接模式不能上网
    python中使用指定GPU
    python开启GPU加速
    Adam那么棒,为什么还对SGD念念不忘 (1) —— 一个框架看懂优化算法
  • 原文地址:https://www.cnblogs.com/CCBB/p/3980856.html
Copyright © 2011-2022 走看看