Para que serve a palavra-chave nativa em Java?

Respostas:

343

A nativepalavra-chave é aplicada a um método para indicar que o método é implementado no código nativo usando JNI (Java Native Interface).

SLaks
fonte
3
A implementação real não precisa usar o JNI. Certos métodos JRE são tratados intrinsecamente pela JVM. De fato, nem é obrigatório que a implementação seja realmente um código nativo . É apenas "implementado em uma linguagem diferente da linguagem de programação Java" .
Holger
444

Exemplo mínimo executável

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));
    }
}

Main.c

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

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

Compile e execute:

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

Resultado:

4

Testado no Ubuntu 14.04 AMD64. Também trabalhou com o Oracle JDK 1.8.0_45.

Exemplo no GitHub para você brincar.

Os sublinhados nos nomes de pacotes / arquivos Java devem ser escapados _1no nome da função C, conforme mencionado em: Chamando Funções JNI no nome do pacote Android que contém sublinhado

Interpretação

native permite que você:

  • chame uma biblioteca compilada dinamicamente carregada (aqui escrita em C) com código de montagem arbitrário de Java
  • e obtenha resultados novamente em Java

Isso pode ser usado para:

  • escreva código mais rápido em uma seção crítica com melhores instruções de montagem da CPU (não é portátil)
  • faça chamadas diretas ao sistema (não é portátil)

com a troca de menor portabilidade.

Também é possível chamar Java de C, mas você deve primeiro criar uma JVM em C: Como chamar funções Java de C ++?

APIs de extensão nativas análogas também estão presentes em muitas outras "linguagens de VM" pelos mesmos motivos, por exemplo , Python , Node.js , Ruby .

Android NDK

O conceito é exatamente o mesmo neste contexto, exceto que você precisa usar o clichê do Android para configurá-lo.

O repositório oficial do NDK contém exemplos "canônicos", como o aplicativo hello-jni:

Em unzipum .apkNDK no Android O, é possível ver o pré-compilado .soque corresponde ao código nativo em lib/arm64-v8a/libnative-lib.so.

TODO confirma: além disso, file /data/app/com.android.appname-*/oat/arm64/base.odexdiz que é uma biblioteca compartilhada, que eu acho que é o .dex pré-compilado AOT correspondente aos arquivos Java no ART, veja também: O que são arquivos ODEX no Android? Talvez o Java também seja executado através de uma nativeinterface?

Exemplo no OpenJDK 8

Vamos encontrar onde Object#cloneé definido em jdk8u60-b27.

Concluiremos que é implementado com uma nativechamada.

Primeiro encontramos:

find . -name Object.java

o que nos leva a jdk / src / share / classes / java / lang / Object.java # l212 :

protected native Object clone() throws CloneNotSupportedException;

Agora vem a parte difícil, descobrir onde o clone está em meio a toda a indireção. A consulta que me ajudou foi:

find . -iname object.c

que encontraria arquivos C ou C ++ que podem implementar os métodos nativos do Object. Isso nos leva ao 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]));
}

o que nos leva ao JVM_Clonesímbolo:

grep -R JVM_Clone

o que nos leva ao hotspot / src / share / vm / prims / jvm.cpp # l580 :

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

Depois de expandir um monte de macros, chegamos à conclusão de que esse é o ponto de definição.

Ciro Santilli adicionou uma nova foto
fonte
1
Excelente resposta. Apenas uma nota de rodapé: para um static nativemétodo Java, o segundo parâmetro da função C ++ é do tipo jclasse não jobject.
SR_ 18/03/19
@ SR_ obrigado pela informação. Houve um erro na minha resposta ou são apenas algumas informações extras?
Ciro Santilli # 19/18
2
@Ciro, são algumas informações extras para quem começa com o seu exemplo (uma resposta com cerca de 300 no SO pode servir como referência). Eu tive uma função com uma assinatura incorreta chamada com uma bagunça na pilha, sem nenhum erro relatado (em qualquer tempo de compilação, link ou execução). Por isso, acho importante mencionar o cuidado nesta etapa.
19318 SR_
419

Ele marca um método, que será implementado em outras linguagens, não em Java. Ele trabalha em conjunto com o JNI (Java Native Interface).

Métodos nativos foram usados ​​no passado para escrever seções críticas de desempenho, mas com o Java ficando mais rápido, isso agora é menos comum. Atualmente, métodos nativos são necessários quando

  • Você precisa chamar uma biblioteca de Java escrita em outra linguagem.

  • Você precisa acessar os recursos do sistema ou hardware acessíveis somente a partir de outro idioma (normalmente C). Na verdade, muitas funções do sistema que interagem com o computador real (E / S de disco e rede, por exemplo) só podem fazer isso porque chamam código nativo.

Consulte também Especificação da interface nativa Java

Orhan Cinar
fonte
3
Este é o meu entendimento de que escrevo System.currentTimeMillis () (que é nativo) no arquivo java e, para funcionar, o JNI chama bibliotecas ou algumas funções escritas em C ou C ++ ou linguagem assembly e retorna algum valor ao meu código java . ex: aqui o método currentTimeMillis chama um código nativo com a ajuda da JNI e esse código nativo fala com o recurso do sistema ex: um timer sentado na placa-mãe e, assim, obtendo valor de retorno (hora do sistema). me corrija por favor?
MKod
4
Os métodos @MKod como currentTimeMillisfazem parte do JDK e são anotados nativeporque a implementação está no próprio código-fonte do JDK. É muito improvável que a implementação use linguagem assembly; provavelmente chama um método API do sistema operacional no qual a JVM está sendo executada. Por exemplo, no Windows, ele pode chamar um método DLL GetSystemTimeno kernel32.dll. Em outro sistema operacional, ele terá uma implementação diferente. No entanto, ao usar nativeum método que você está escrevendo (em oposição a um método JDK), é necessário fornecer a implementação usando JNI.
Adam Burley
Esta declaração é importante para a palavra-chave Nativa ... 'Você precisa acessar os recursos do sistema ou de hardware acessíveis apenas a partir do outro idioma (normalmente o C)'.
Atiqkhaled
@Kidburla Posso perguntar o que você quer dizer com "a implementação está no próprio código-fonte do JDK"? currentTimeMillisestá marcado como nativo java.lang.Systempara usar JNI, não é?
flow2k
1
@ flow2k sim, o que você disse é provavelmente verdade, eu não sei por que eu disse isso no meu comentário (mais de 2 anos atrás)
Adam Burley
59

Straight from a especificação Java Idioma :

Um método nativeimplementado no código dependente da plataforma, normalmente escrito em outra linguagem de programação, como C, C ++, FORTRAN ou linguagem assembly. O corpo de um nativemétodo é fornecido apenas como ponto e vírgula, indicando que a implementação foi omitida, em vez de um bloco.

Pops
fonte
19

Como SLaks respondeu, o native palavra-chave é para chamar código nativo.

Também é usado pelo GWT para implementar métodos javascript.

Melv
fonte
13

funções que implementam código nativo são declaradas nativas.

A Java Native Interface (JNI) é uma estrutura de programação que permite que o código Java em execução em uma Java Virtual Machine (JVM) chame e seja chamado por aplicativos nativos (programas específicos para uma plataforma de hardware e sistema operacional) e bibliotecas escritas em outras linguagens como C, C ++ e assembly.

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

Adelin
fonte
8

NATIVE é Modificador sem acesso. Só pode ser aplicado a METHOD. Indica a implementação do método ou código PLATAFORMA-DEPENDENTE.

Reetika
fonte
6

native é uma palavra-chave em java, usada para tornar a estrutura (método) não implementada como abstrata, mas seria dependente da plataforma, como código nativo, e executada a partir da pilha nativa e não da pilha java.

Sarfaraz Ahamad Shaikh
fonte
6
  • native é uma palavra-chave em java, indica dependente da plataforma.
  • nativemétodos são atos como interface entre Java ( JNI ) e outras linguagens de programação.
Premraj
fonte
3

O nativemétodo Java fornece um mecanismo para o código Java chamar o código nativo do SO, devido a razões funcionais ou de desempenho.

Exemplo:

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();

No Runtime.classarquivo correspondente no OpenJDK, localizado em JAVA_HOME/jmods/java.base.jmod/classes/java/lang/Runtime.class, contém esses métodos e os marcou com ACC_NATIVE( 0x0100), e esses métodos não contêm o atributo Code , o que significa que esse método não possui nenhuma lógica de codificação real no Runtime.classarquivo:

  • Método 13 availableProcessors: marcado como atributo nativo e sem código
  • Método 14 freeMemory: marcado como atributo nativo e sem código
  • Método 15 totalMemory: marcado como atributo nativo e sem código
  • Método 16 maxMemory: marcado como atributo nativo e sem código
  • Método 17 gc: marcado como atributo nativo e sem código

insira a descrição da imagem aqui

A lógica de codificação de fato está no arquivo Runtime.c correspondente :

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  }

E essa Ccodificação é compilada no arquivo libjava.so(Linux) ou libjava.dll(Windows), localizado em JAVA_HOME/jmods/java.base.jmod/lib/libjava.so:

insira a descrição da imagem aqui

insira a descrição da imagem aqui

Referência

Feliz
fonte