2009-06-18 31 views

Respuesta

90

Las otras respuestas son técnicamente correctas, pero no muy útiles para alguien sin experiencia en JNI. :-)

Normalmente, para que la JVM encuentre sus funciones nativas, deben nombrarse de cierta manera. por ejemplo, para java.lang.Object.registerNatives, la función C correspondiente se llama Java_java_lang_Object_registerNatives. Al usar registerNatives (o más bien, la función JNI RegisterNatives), puede asignarle el nombre que desee a sus funciones C.

Aquí está el código asociado C (de OpenJDK 6):

static JNINativeMethod methods[] = { 
    {"hashCode", "()I",     (void *)&JVM_IHashCode}, 
    {"wait",  "(J)V",     (void *)&JVM_MonitorWait}, 
    {"notify",  "()V",     (void *)&JVM_MonitorNotify}, 
    {"notifyAll", "()V",     (void *)&JVM_MonitorNotifyAll}, 
    {"clone",  "()Ljava/lang/Object;", (void *)&JVM_Clone}, 
}; 

JNIEXPORT void JNICALL 
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls) 
{ 
    (*env)->RegisterNatives(env, cls, 
          methods, sizeof(methods)/sizeof(methods[0])); 
} 

(Nótese que Object.getClass no está en la lista, sino que seguirá siendo llamado por el nombre de "estándar" de Java_java_lang_Object_getClass.) Para las funciones en la lista, las funciones C asociadas se enumeran en esa tabla, lo que es más útil que escribir un grupo de funciones de reenvío.

El registro de funciones nativas también es útil si incorpora Java en su programa C y desea vincularlo con funciones dentro de la propia aplicación (a diferencia de una biblioteca compartida) o las funciones utilizadas no se "exportan" ", ya que estos normalmente no se encuentran por el mecanismo de búsqueda de método estándar. El registro de funciones nativas también se puede utilizar para "volver a enlazar" un método nativo a otra función C (útil si su programa admite cargar y descargar módulos dinámicamente, por ejemplo).

Animo a todos a leer el JNI book, que habla de esto y mucho más. :-)

+1

Usted escribió nombre de función JNI completamente decorado, lo que lo hace confuso: es 'Java_java_lang_Object_registerNatives' llamado por VM automáticamente, o el código c/C++ tiene que llamar a esa función y no hay necesidad de todo java gobblygook – Pavel

+0

@Pavel Por defecto, un el método nativo 'methodName' en la clase' fully.qualified.ClassName' se busca con el nombre de C 'Java_fully_qualified_ClassName_methodName' (que debe exportar el código del lado C). Puede llamar al método 'RegisterNatives' de' JNIEnv' para anular este enlace. En otras palabras, si no usa 'RegisterNatives' primero," se requiere todo lo que java gobblygook "[sic]. –

+0

Ah, de acuerdo, al exportar solo 1 función 'Java_java_lang_Object_registerNatives', puedo vincular todas mis cosas JNI comprobando el valor de' cls'. Me perdí la parte de que registerNatives es en realidad parte de Java. Entonces ... cuando se va a utilizar alguna clase, ¿cuál es el orden de las acciones que JVM usa para vincular a los nativos? Parece que si los nativos no están registrados todavía (de c/C++), entonces JVM busca todos estos nombres exportados, si no están presentes, entonces intenta usar Object.registerNatives (¿o al revés?). Por cierto, el enlace del libro jni está muerto. – Pavel

-9

Ya que miró el código fuente para encontrarlo, es bastante fácil de adivinar ¿no?

Es un método nativo, y se llama registerNatives, así que supongo que registra objetos con la plataforma subyacente.

También es privado, por lo que probablemente no hay nada de qué preocuparse.

+20

Debe ser un programador de código cerrado ("seguir adelante, nada que ver"), no acostumbrado a la idea de que las personas realmente quieran saber qué sucede "debajo de las sábanas". Basta de charla. :-P –

+2

Maldita sea, era tan obvio, ¿verdad? – aberrant80

8

Lo que podría ser un poco confuso es que el código mostrado para java.lang.Object.registerNatives en una respuesta anterior es solo un ejemplo de cómo registrar funciones nativas. Este es el código que (en la implementación de OpenJDK) registra funciones nativas para Object de clase. Para registrar funciones nativas para su propia clase, debe llamar a la función JNI RegisterNatives desde el código nativo en su propia biblioteca. Esto puede sonar un poco circular, pero hay un par de maneras de romper el ciclo.

  1. seguir el ejemplo de esta implementación de la clase Object:

    a. En su clase de Java, declare un método nativo (preferiblemente estático) llamado registerNatives (o cualquier otro nombre, no importa).

    b. En su código nativo, defina una función llamada Java_<your fully qualified class name>_registerNatives, que contiene una llamada a la función JNI RegisterNatives.

    c. Asegúrese de que en su código Java, se llame a su método Java registerNatives antes de cualquier llamada a otros métodos nativos.

O

  1. Uso JNI_OnLoad

    a. En su biblioteca nativa, defina una función jint JNI_OnLoad(JavaVM *vm, void *reserved). En el cuerpo de esta función, llame a la función JNI RegisterNatives.

    b. La máquina virtual Java buscará automáticamente y llamará al JNI_OnLoad cuando su biblioteca nativa esté cargada por System.loadLibrary, que ya debería estar llamando, probablemente en un inicializador estático para su clase. (Se obtiene el puntero env requerido llamando a la función GetEnv en la tabla que los vm puntero apunta a.)