¿Para qué es la palabra clave nativa en Java?

Respuestas:

343

La nativepalabra clave se aplica a un método para indicar que el método se implementa en código nativo utilizando JNI (Java Native Interface).

SLaks
fuente
3
La implementación real no tiene que usar JNI. Ciertos métodos JRE son manejados intrínsecamente por la JVM. De hecho, ni siquiera es obligatorio que la implementación sea en realidad código nativo . Simplemente está "implementado en un lenguaje diferente al lenguaje de programación Java" .
Holger
444

Ejemplo ejecutable mínimo

Main.java

public class Main {
    public native int square(int i);
    public static void main(String[] args) {
        System.loadLibrary("Main");
        System.out.println(new Main().square(2));
    }
}

C Principal

#include <jni.h>
#include "Main.h"

JNIEXPORT jint JNICALL Java_Main_square(
    JNIEnv *env, jobject obj, jint i) {
  return i * i;
}

Compilar y ejecutar:

sudo apt-get install build-essential openjdk-7-jdk
export JAVA_HOME='/usr/lib/jvm/java-7-openjdk-amd64'
javac Main.java
javah -jni Main
gcc -shared -fpic -o libMain.so -I${JAVA_HOME}/include \
  -I${JAVA_HOME}/include/linux Main.c
java -Djava.library.path=. Main

Salida:

4

Probado en Ubuntu 14.04 AMD64. También trabajó con Oracle JDK 1.8.0_45.

Ejemplo en GitHub para que juegues.

Los caracteres de subrayado en los nombres de paquete / archivo Java deben escaparse con _1el nombre de la función C como se menciona en: Invocación de funciones JNI en el nombre del paquete de Android que contiene guión bajo

Interpretación

native Te permite:

  • llame a una biblioteca compilada cargada dinámicamente (aquí escrita en C) con código de ensamblaje arbitrario de Java
  • y obtener resultados de nuevo en Java

Esto podría usarse para:

  • escriba un código más rápido en una sección crítica con mejores instrucciones de ensamblaje de la CPU (no CPU portátil)
  • hacer llamadas directas al sistema (no OS portátil)

con el compromiso de una menor portabilidad.

También es posible que llame a Java desde C, pero primero debe crear una JVM en C: ¿Cómo llamar a las funciones de Java desde C ++?

Las API de extensiones nativas análogas también están presentes en muchos otros "lenguajes VM" por las mismas razones, por ejemplo , Python , Node.js , Ruby .

Android NDK

El concepto es exactamente el mismo en este contexto, excepto que tiene que usar la plantilla de Android para configurarlo.

El repositorio oficial de NDK contiene ejemplos "canónicos" como la aplicación hello-jni:

En usted unzipy .apkcon NDK en Android O, puede ver el precompilado .soque corresponde al código nativo debajo lib/arm64-v8a/libnative-lib.so.

TODO confirma: además, file /data/app/com.android.appname-*/oat/arm64/base.odexdice que es una biblioteca compartida, que creo que es el .dex precompilado AOT correspondiente a los archivos Java en ART, vea también: ¿Qué son los archivos ODEX en Android? Entonces, ¿tal vez Java también se ejecute a través de una nativeinterfaz?

Ejemplo en OpenJDK 8

Busquemos encontrar dónde Object#clonese define en jdk8u60-b27.

Concluiremos que se implementa con una nativellamada.

Primero encontramos:

find . -name Object.java

lo que nos lleva a jdk / src / share / classes / java / lang / Object.java # l212 :

protected native Object clone() throws CloneNotSupportedException;

Ahora viene la parte difícil, encontrar dónde está el clon en medio de toda la indirección. La consulta que me ayudó fue:

find . -iname object.c

que encontraría archivos C o C ++ que podrían implementar los métodos nativos de Object. Nos lleva a jdk / share / native / java / lang / Object.c # l47 :

static JNINativeMethod methods[] = {
    ...
    {"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]));
}

lo que nos lleva al JVM_Clonesímbolo:

grep -R JVM_Clone

lo que nos lleva a hotspot / src / share / vm / prims / jvm.cpp # l580 :

JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
    JVMWrapper("JVM_Clone");

Después de expandir un montón de macros, llegamos a la conclusión de que este es el punto de definición.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
1
Excelente respuesta Solo una nota al pie: para un static nativemétodo Java, el segundo parámetro de la función C ++ es de tipo jclassy no jobject.
SR_
@SR_ gracias por la información. ¿Hubo un error en mi respuesta o es solo información adicional?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
2
@Ciro es información adicional para aquellos que comienzan con su ejemplo (una respuesta con aproximadamente 300 en SO puede servir como referencia). He tenido una función con una firma incorrecta llamada con un desorden en la pila, sin errores reportados (en ninguno de los tiempos de compilación, enlace o ejecución). Por lo tanto, me parece importante mencionar que tenga cuidado en este paso.
SR_
419

Marca un método, que se implementará en otros idiomas, no en Java. Funciona junto con JNI (Java Native Interface).

Los métodos nativos se usaron en el pasado para escribir secciones críticas de rendimiento, pero con Java cada vez más rápido, esto ahora es menos común. Actualmente se necesitan métodos nativos cuando

  • Debe llamar a una biblioteca desde Java que esté escrita en otro idioma.

  • Debe acceder a los recursos del sistema o hardware a los que solo se puede acceder desde el otro lenguaje (generalmente C). En realidad, muchas funciones del sistema que interactúan con una computadora real (disco y red IO, por ejemplo) solo pueden hacer esto porque llaman código nativo.

Consulte también la especificación de la interfaz nativa de Java

Orhan Cinar
fuente
3
Según tengo entendido, escribo System.currentTimeMillis () (que es nativo) en el archivo java y luego para que funcione, JNI llamará a las bibliotecas o algunas funciones escritas en C o C ++ o lenguaje ensamblador y luego devolveré algún valor a mi código java . ex: aquí el método currentTimeMillis invoca un código nativo con la ayuda de JNI y ese código nativo habla con el recurso del sistema ex: un temporizador que se encuentra en la placa base y así obtiene el valor de retorno (hora del sistema). corrígeme, por favor?
MKod
44
Los métodos @MKod como currentTimeMillisson parte del JDK y están anotados nativeporque la implementación está en el código fuente JDK. Es muy poco probable que la implementación use lenguaje ensamblador; probablemente llama a un método API del sistema operativo sobre el cual se ejecuta la JVM. Por ejemplo, en Windows puede llamar a un método DLL GetSystemTimeen kernel32.dll. En otro sistema operativo tendrá una implementación diferente. Sin embargo, cuando utiliza nativepara un método que está escribiendo (a diferencia de un método JDK), debe proporcionar la implementación utilizando JNI.
Adam Burley
Esta declaración es importante para la palabra clave nativa ... 'Debe acceder a los recursos del sistema o hardware a los que solo se puede acceder desde el otro idioma (generalmente C)'.
atiqkhaled
@Kidburla ¿Puedo preguntar qué quiere decir con "la implementación está en el código fuente JDK en sí"? currentTimeMillisestá marcado como nativo, por java.lang.Systemlo que usa JNI, ¿no es así?
flow2k
1
@ flow2k sí, lo que ha dicho es probablemente cierto, no estoy seguro de por qué lo dije en mi comentario (hace más de 2 años)
Adam Burley
59

Directamente desde la especificación del lenguaje Java :

Un método que se nativeimplementa en código dependiente de la plataforma, normalmente escrito en otro lenguaje de programación como C, C ++, FORTRAN o lenguaje ensamblador. El cuerpo de un nativemétodo se proporciona solo como punto y coma, lo que indica que se omite la implementación, en lugar de un bloque.

Estallidos
fuente
19

Como respondió SLaks, la nativepalabra clave es para llamar a código nativo.

También lo utiliza GWT para implementar métodos javascript.

Melv
fuente
13

Las funciones que implementan código nativo se declaran nativas.

La interfaz nativa de Java (JNI) es un marco de programación que permite que el código Java que se ejecuta en una máquina virtual Java (JVM) invoque, y sea llamado por, aplicaciones nativas (programas específicos para una plataforma de hardware y sistema operativo) y bibliotecas escritas en otros lenguajes como C, C ++ y ensamblaje.

http://en.wikipedia.org/wiki/Java_Native_Interface

Adelin
fuente
8

NATIVE es un modificador sin acceso. Solo se puede aplicar a METHOD. Indica la implementación DEPENDIENTE DE LA PLATAFORMA del método o código.

Reetika
fuente
6

native es una palabra clave en java, que se usa para hacer que la estructura (método) no implementada sea abstracta, pero dependería de la plataforma, como el código nativo, y se ejecutaría desde la pila nativa, no desde la pila java.

Sarfaraz Ahamad Shaikh
fuente
6
  • native es una palabra clave en java, indica que depende de la plataforma.
  • nativeLos métodos son actos como interfaz entre Java ( JNI ) y otros lenguajes de programación.
Premraj
fuente
3

El nativemétodo Java proporciona un mecanismo para que el código Java llame al código nativo del sistema operativo, ya sea por razones funcionales o de rendimiento.

Ejemplo:

606  public native int availableProcessors();
617  public native long freeMemory();
630  public native long totalMemory();
641  public native long maxMemory();
664  public native void gc();

En el Runtime.classarchivo correspondiente en OpenJDK, ubicado en JAVA_HOME/jmods/java.base.jmod/classes/java/lang/Runtime.class, contiene estos métodos y los etiquetó con ACC_NATIVE( 0x0100), y estos métodos no contienen el atributo Code , lo que significa que estos métodos no tienen ninguna lógica de codificación real en el Runtime.classarchivo:

  • Método 13 availableProcessors: etiquetado como atributo nativo y sin código
  • Método 14 freeMemory: etiquetado como atributo nativo y sin código
  • Método 15 totalMemory: etiquetado como atributo nativo y sin código
  • Método 16 maxMemory: etiquetado como atributo nativo y sin código
  • Método 17 gc: etiquetado como atributo nativo y sin código

ingrese la descripción de la imagen aquí

De hecho, la lógica de codificación está en el archivo Runtime.c correspondiente :

42  #include "java_lang_Runtime.h"
43
44  JNIEXPORT jlong JNICALL
45  Java_java_lang_Runtime_freeMemory(JNIEnv *env, jobject this)
46  {
47      return JVM_FreeMemory();
48  }
49
50  JNIEXPORT jlong JNICALL
51  Java_java_lang_Runtime_totalMemory(JNIEnv *env, jobject this)
52  {
53      return JVM_TotalMemory();
54  }
55
56  JNIEXPORT jlong JNICALL
57  Java_java_lang_Runtime_maxMemory(JNIEnv *env, jobject this)
58  {
59      return JVM_MaxMemory();
60  }
61
62  JNIEXPORT void JNICALL
63  Java_java_lang_Runtime_gc(JNIEnv *env, jobject this)
64  {
65      JVM_GC();
66  }
67  
68  JNIEXPORT jint JNICALL
69  Java_java_lang_Runtime_availableProcessors(JNIEnv *env, jobject this)
70  {
71      return JVM_ActiveProcessorCount();
72  }

Y esta Ccodificación se compila en el archivo libjava.so(Linux) o libjava.dll(Windows), ubicado en JAVA_HOME/jmods/java.base.jmod/lib/libjava.so:

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Referencia

Contento
fuente