Mientras jugaba este rompecabezas (es un juego de trivia de palabras clave de Java), me encontré con la native
palabra clave.
¿Para qué se usa la palabra clave nativa en Java?
Mientras jugaba este rompecabezas (es un juego de trivia de palabras clave de Java), me encontré con la native
palabra clave.
¿Para qué se usa la palabra clave nativa en Java?
Respuestas:
La native
palabra clave se aplica a un método para indicar que el método se implementa en código nativo utilizando JNI (Java Native Interface).
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 _1
el 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:
Esto podría usarse para:
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 unzip
y .apk
con NDK en Android O, puede ver el precompilado .so
que 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.odex
dice 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 native
interfaz?
Ejemplo en OpenJDK 8
Busquemos encontrar dónde Object#clone
se define en jdk8u60-b27.
Concluiremos que se implementa con una native
llamada.
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_Clone
sí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.
static
native
método Java, el segundo parámetro de la función C ++ es de tipo jclass
y no jobject
.
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
currentTimeMillis
son parte del JDK y están anotados native
porque 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 GetSystemTime
en kernel32.dll. En otro sistema operativo tendrá una implementación diferente. Sin embargo, cuando utiliza native
para un método que está escribiendo (a diferencia de un método JDK), debe proporcionar la implementación utilizando JNI.
currentTimeMillis
está marcado como nativo, por java.lang.System
lo que usa JNI, ¿no es así?
Directamente desde la especificación del lenguaje Java :
Un método que se
native
implementa 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 unnative
método se proporciona solo como punto y coma, lo que indica que se omite la implementación, en lugar de un bloque.
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.
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.
El native
mé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.class
archivo 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.class
archivo:
availableProcessors
: etiquetado como atributo nativo y sin códigofreeMemory
: etiquetado como atributo nativo y sin códigototalMemory
: etiquetado como atributo nativo y sin códigomaxMemory
: etiquetado como atributo nativo y sin códigogc
: etiquetado como atributo nativo y sin códigoDe 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 C
codificación se compila en el archivo libjava.so
(Linux) o libjava.dll
(Windows), ubicado en JAVA_HOME/jmods/java.base.jmod/lib/libjava.so
:
Referencia