2010年10月6日 星期三

JNI - Invoking Constructors

In the JNI, constructors may be invoked following steps similar to those used for calling instance methods.
    Invoke constructors as following steps:
  1. To obtain the method ID of a constructor, pass "<init>" as the method name and "V" as the return type in the method descriptor.
  2. To invoke the constructor by passing the method ID to JNI functions such as NewObject.
  3. (Example) The following code implements the equivalent functionality of the JNI function NewString, which constructs a java.lang.String object from the Unicode characters stored in a C buffer:
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;
}
  1. FindClass(): returns a reference to the java.lang.String class.
  2. GetMethodID(): returns the method ID for the string constructor, String(char[] chars).
  3. NewCharArray(): to allocate a character array that holds all the string elements.
  4. NewObject(): invokes the constructor specified by the method ID.
  5. DeleteLocalRef(): allows the virtual machine to free the resources used by local references elemArr and stringClass.
It is also possible to invoke constructors using the CallNonvirtualVoidMethod function.
    result = (*env)->NewObject(env, stringClass, cid, elemArr);
  • The single NewObject call above may be replaced by an AllocObject call followed by a CallNonvirtualVoidMethod call:
  • 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;
        }
    }
    
    AllocObject(): creates an uninitialized object.
    CallNonvirtualVoidMethod(): invokes constructors.
    In most cases, however, you should use NewObject and avoid the more error-prone AllocObject/CallNonvirtualVoidMethod pair.

0 意見: