美文网首页
JNI学习记录5-Methods

JNI学习记录5-Methods

作者: ai___believe | 来源:发表于2017-03-03 18:00 被阅读128次

    JNI学习记录1-初建JNI工程
    JNI学习记录2-local refence崩溃问题
    JNI学习记录3-String and Array
    JNI学习记录4-Fields
    JNI学习记录5-Methods

    Java中有三类方法:实例方法、静态方法和构造方法。

    一、Calling Methods

    java:

    class InstanceMethodCall {
    private native void nativeMethod();
    private void callback() {
    System.out.println("In Java");
    }
    public static void main(String args[]) {
    InstanceMethodCall c = new InstanceMethodCall();
    c.nativeMethod();
    }
    static {
    System.loadLibrary("InstanceMethodCall");
    }
    }

    JNI:

    JNIEXPORT void JNICALL
    Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj)
    {
    jclass cls = (*env)->GetObjectClass(env, obj);
    jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "()V");
    if (mid == NULL) {
    return; /* method not found */
    }
    printf("In C\n");
    (*env)->CallVoidMethod(env, obj, mid);
    }

    回调Java方法分两步:

    • 首先通过GetMethodID在给定类中查询方法. 查询基于方法名称和签名
    • 本地方法调用CallVoidMethod,该方法表明被调Java方法的返回值为void

    二、Calling Static Methods

    同实例方法,回调Java静态方法分两步:

    • 首先通过GetStaticMethodID在给定类中查找方法
    • 通过CallStatic<ReturnValueType>Method调用
      静态方法与实例方法的不同,前者传入参数为jclass,后者为jobject

    三、Calling Instance Methods of a Superclass

    调用被子类覆盖的父类方法: JNI支持用CallNonvirtual<Type>Method满足这类需求:

    • GetMethodID获得method ID
    • 调用CallNonvirtualVoidMethod, CallNonvirtualBooleanMethod
      上述,等价于如下Java语言的方式:
      super.f();
      CallNonvirtualVoidMethod可以调用构造函数

    四、Invoking Constructors

    jstring MyNewString(JNIEnv *env, jchar *chars, jint len)
    {
    jclass stringClass;
    jmethodID cid;
    jcharArray elemArr;
    jstring result;
    stringClass = (*env)->FindClass(env, "java/lang/String");
    if (stringClass == NULL) {
    return NULL; /* exception thrown\ /
    }
    /* Get the method ID for the String(char[]) constructor */
    cid = (*env)->GetMethodID(env, stringClass, "<init>", "([C)V");
    if (cid == NULL) {
    return NULL; /* exception thrown */
    }
    /* Create a char[] that holds the string characters */
    elemArr = (*env)->NewCharArray(env, len);
    if (elemArr == NULL) {
    return NULL; /* exception thrown */
    }
    (
    env)->SetCharArrayRegion(env, elemArr, 0, len, chars);
    /* Construct a java.lang.String object */
    result = (*env)->NewObject(env, stringClass, cid, elemArr);
    /* Free local references */
    (*env)->DeleteLocalRef(env, elemArr);
    (*env)->DeleteLocalRef(env, stringClass);
    return result;
    }

    首先,FindClass找到java.lang.String的jclass. 接下来,用GetMethodID找到构造
    函数String(char[] chars)的MethodID. 此时用NewCharArray分配一个Char数组对象。
    NewObject调用构造函数。
    用DeleteLocalRef释放资源。
    注意NewString是个常用函数,所以在JNI中直接被支持了,并且该函数的实现要比我们
    实现的高效。
    也可使用CallNonvirtualVoidMehtod调用构造函数. 如下代码:
    result = (*env)->NewObject(env, stringClass, cid, elemArr);
    可被替换为:

    result = (*env)->AllocObject(env, stringClass);
    if (result) {
    (*env)->CallNonvirtualVoidMethod(env, result, stringClass, cid,
    elemArr);
    /* we need to check for possible exceptions */
    if ((*env)->ExceptionCheck(env)) {
    (*env)->DeleteLocalRef(env, result);
    result = NULL;
    }

    五、Caching at the Point of Use

    JNIEXPORT void JNICALL
    Java_InstanceFieldAccess_accessField(JNIEnv *env, jobject obj)
    {
    static jfieldID fid_s = NULL; /* cached field ID for s */
    jclass cls = (\*env)->GetObjectClass(env, obj);
    jstring jstr;
    const char str;
    if (fid_s == NULL) {
    fid_s = (
    env)->GetFieldID(env, cls, "s",
    "Ljava/lang/String;");
    if (fid_s == NULL) {
    return; /* exception already thrown /
    }
    }
    printf("In C:\n");
    jstr = (
    env)->GetObjectField(env, obj, fid_s);
    str = (env)->GetStringUTFChars(env, jstr, NULL);
    if (str == NULL) {
    return; /* out of memory */
    }
    printf(" c.s = "%s"\n", str);
    (
    env)->ReleaseStringUTFChars(env, jstr, str);
    jstr = (env)->NewStringUTF(env, "123");
    if (jstr == NULL) {
    return; /* out of memory */
    }
    (
    env)->SetObjectField(env, obj, fid_s, jstr);
    }

    如上,静态变量fid_s保存了InstanceFieldAccess.s的filed ID。初始化阶段静态变量
    被赋值为NULL。第一调用InstanceFieldAccess.accessField时,缓存fieldID以待后用。
    你可能会发现上述代码有个竞争条件,当多个线程同时访问此函数时,可能会同时计算一
    个field ID. 没关系,此处的竞争是无害的,因为即使在多个线程中同时计算该field
    ID,各线程中的计算结果都是一样的。

    相关文章

      网友评论

          本文标题:JNI学习记录5-Methods

          本文链接:https://www.haomeiwen.com/subject/pzurgttx.html