Do czego służy natywne słowo kluczowe w Javie?

Odpowiedzi:

343

Słowo nativekluczowe jest stosowane do metody, aby wskazać, że metoda jest zaimplementowana w kodzie natywnym przy użyciu JNI (Java Native Interface).

SLaks
źródło
3
Rzeczywista implementacja nie musi korzystać z JNI. Niektóre metody JRE są obsługiwane wewnętrznie przez JVM. W rzeczywistości nie jest nawet obowiązkowe, aby implementacja była faktycznie rodzimym kodem. Jest po prostu „zaimplementowany w języku innym niż język programowania Java” .
Holger
443

Minimalny możliwy do uruchomienia przykład

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

Skompiluj i uruchom:

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

Wynik:

4

Testowany na Ubuntu 14.04 AMD64. Współpracował również z Oracle JDK 1.8.0_45.

Przykład na GitHub, z którym możesz grać.

Podkreślenia w nazwach pakietów / plików Java muszą być poprzedzane znakami ucieczki _1w nazwie funkcji C, jak wspomniano w: Wywoływanie funkcji JNI w nazwie pakietu Android zawierającej podkreślenie

Interpretacja

native pozwala Ci na:

  • wywołać skompilowaną dynamicznie ładowaną bibliotekę (tutaj napisaną w C) z dowolnym kodem asemblera z Javy
  • i uzyskaj wyniki z powrotem w Javie

Można to wykorzystać do:

  • pisz szybszy kod w krytycznej sekcji z lepszymi instrukcjami montażu procesora (nie przenośny procesor)
  • nawiązywać bezpośrednie połączenia systemowe (nieprzenośne dla systemu operacyjnego)

z kompromisem niższej przenośności.

Możliwe jest również wywoływanie Java z C, ale najpierw musisz utworzyć JVM w C: Jak wywoływać funkcje Java z C ++?

Android NDK

W tym kontekście koncepcja jest dokładnie taka sama, z tym wyjątkiem, że do jej skonfigurowania trzeba użyć podstawki Android.

Oficjalne repozytorium NDK zawiera „kanoniczne” przykłady, takie jak aplikacja hello-jni:

W was unzipna .apkz NDK na Androida O, widać skompilowane .soktóry odpowiada natywnego kodu pod lib/arm64-v8a/libnative-lib.so.

TODO potwierdź: co więcej, file /data/app/com.android.appname-*/oat/arm64/base.odexmówi, że jest to biblioteka współdzielona, ​​która, jak myślę, jest wstępnie skompilowaną AOT .dex odpowiadającą plikom Java w ART, zobacz także: Co to są pliki ODEX w Androidzie? Więc może Java jest również uruchamiana przez nativeinterfejs?

Przykład w OpenJDK 8

Znajdźmy gdzie Object#clonejest zdefiniowany w jdk8u60-b27.

Dochodzimy do wniosku, że jest on realizowany za pomocą nativepołączenia.

Najpierw znajdujemy:

find . -name Object.java

co prowadzi nas do jdk / src / share / klas / java / lang / Object.java # l212 :

protected native Object clone() throws CloneNotSupportedException;

Teraz przychodzi trudna część, znalezienie miejsca, w którym klon znajduje się pośród całej pośrednictwa. Zapytanie, które mi pomogło, to:

find . -iname object.c

który znalazłby pliki C lub C ++, które mogłyby implementować rodzime metody Object. Prowadzi nas do 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]));
}

co prowadzi nas do JVM_Clonesymbolu:

grep -R JVM_Clone

co prowadzi nas do hotspot / src / share / vm / prims / jvm.cpp # l580 :

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

Po rozwinięciu kilku makr dochodzimy do wniosku, że jest to punkt definicji.

Ciro Santilli
źródło
1
Doskonała odpowiedź. Tylko przypis: w przypadku static nativemetody Java drugi parametr funkcji C ++ jest typu, jclassa nie typu jobject.
SR_
@SR_ dzięki za informację. Czy moja odpowiedź była błędna, czy to tylko dodatkowe informacje?
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功
2
@Ciro to dodatkowe informacje dla tych, którzy zaczynają od twojego przykładu (odpowiedź z około 300 na SO może służyć jako odniesienie). Mam funkcję z niepoprawną sygnaturą wywoływaną z bałaganem na stosie, bez zgłaszanego błędu (w dowolnym czasie kompilacji, połączenia lub uruchomienia). Dlatego uważam, że należy wspomnieć o tym, aby zachować ostrożność na tym etapie.
SR_
419

Oznacza metodę, że zostanie zaimplementowana w innych językach, a nie w Javie. Współpracuje z JNI (Java Native Interface).

W przeszłości używane były metody rodzime do pisania sekcji krytycznych pod względem wydajności, ale wraz z przyspieszeniem Javy jest to obecnie mniej powszechne. Metody rodzime są obecnie potrzebne, gdy

  • Musisz wywołać bibliotekę z Java napisaną w innym języku.

  • Musisz uzyskać dostęp do zasobów systemowych lub sprzętowych, które są dostępne tylko z innego języka (zazwyczaj C). W rzeczywistości wiele funkcji systemowych, które współdziałają z rzeczywistym komputerem (na przykład dyskowe i sieciowe IO), może to zrobić tylko dlatego, że wywołują kod natywny.

Zobacz także specyfikację Java Native Interface

Orhan Cinar
źródło
3
Rozumiem, że piszę System.currentTimeMillis () (który jest rodzimy) w pliku Java, a następnie to działa, JNI wywoła biblioteki lub niektóre funkcje napisane w C lub C ++ lub języku asemblera, a następnie zwróci pewną wartość z powrotem do mojego kodu Java . Np .: tutaj metoda currentTimeMillis wywołuje kod natywny za pomocą JNI, a ten kod natywny komunikuje się z zasobem systemowym np: licznik czasu siedzi na płycie głównej i w ten sposób otrzymuje wartość zwracaną (czas systemowy). popraw mnie, proszę?
MKod
4
Metody @MKod, takie jak, currentTimeMillissą częścią JDK i są opatrzone adnotacjami, nativeponieważ implementacja jest w samym kodzie źródłowym JDK. Jest bardzo mało prawdopodobne, że implementacja używa języka asemblera; prawdopodobnie wywołuje metodę API systemu operacyjnego, na którym działa JVM. Na przykład w systemie Windows może wywoływać metodę DLL GetSystemTimew pliku kernel32.dll. W innym systemie operacyjnym będzie miał inną implementację. Jednak jeśli używasz nativemetody, którą piszesz (w przeciwieństwie do metody JDK), musisz podać implementację za pomocą JNI.
Adam Burley
To stwierdzenie jest ważne dla słowa kluczowego Native ... „Musisz uzyskać dostęp do zasobów systemowych lub sprzętowych, które są dostępne tylko z drugiego języka (zazwyczaj C)”.
atiqkhaled
@Kidburla Czy mogę zapytać, co masz na myśli przez „wdrożenie jest w samym kodzie źródłowym JDK”? currentTimeMillisjest oznaczony jako natywny, java.lang.Systemwięc używa JNI, prawda?
flow2k
1
@ flow2k tak, to, co powiedziałeś, jest prawdopodobnie prawdą, nie jestem pewien, dlaczego powiedziałem to w moim komentarzu (ponad 2 lata temu)
Adam Burley
59

Prosto z tym Java Language Specification :

Metoda nativezaimplementowana w kodzie zależnym od platformy, zwykle napisanym w innym języku programowania, takim jak C, C ++, FORTRAN lub język asemblera. Treść nativemetody jest podawana tylko jako średnik, co oznacza, że ​​implementacja została pominięta zamiast bloku.

Wyskakuje
źródło
19

W odpowiedzi na SLaks nativesłowo kluczowe służy do wywoływania kodu natywnego.

Używał go także GWT do implementacji metod javascript.

Melv
źródło
13

funkcje implementujące kod macierzysty są deklarowane jako rodzime.

Java Native Interface (JNI) to platforma programistyczna, która umożliwia uruchamianie kodu Java w maszynie wirtualnej Java (JVM) w celu wywoływania i wywoływania przez aplikacje rodzime (programy specyficzne dla platformy sprzętowej i systemu operacyjnego) oraz biblioteki napisane w inne języki, takie jak C, C ++ i asembler.

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

Adelina
źródło
8

NATIVE jest modyfikatorem braku dostępu. Można go stosować tylko do METODY. Wskazuje implementację metody lub kodu w zależności od PLATFORMY.

Reetika
źródło
6

native jest słowem kluczowym w java, które służy do tego, aby niezaimplementowana struktura (metoda) była jak abstrakcyjna, ale byłaby zależna od platformy, takiej jak kod natywny i wykonywana ze stosu natywnego, a nie stosu java.

Sarfaraz Ahamad Shaikh
źródło
6
  • native jest słowem kluczowym w Javie, oznacza zależne od platformy.
  • native metody działają jako interfejs między Javą ( JNI ) a innymi językami programowania.
Premraj
źródło
3

Jawa nativeMetoda zapewnia mechanizm wywoływania przez kod Java natywnego kodu systemu operacyjnego z powodów funkcjonalnych lub wydajnościowych.

Przykład:

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

W odpowiednim Runtime.classpliku w OpenJDK, znajdującym się w JAVA_HOME/jmods/java.base.jmod/classes/java/lang/Runtime.class, zawiera te metody i oznacza je za pomocą ACC_NATIVE( 0x0100), a metody te nie zawierają atrybutu Code , co oznacza, że ​​metody te nie mają żadnej logiki kodowania w Runtime.classpliku:

  • Metoda 13 availableProcessors: oznaczona jako natywna i bez atrybutu Kod
  • Metoda 14 freeMemory: oznaczona jako natywna i bez atrybutu Kod
  • Metoda 15 totalMemory: oznaczona jako natywna i bez atrybutu Kod
  • Metoda 16 maxMemory: oznaczona jako natywna i bez atrybutu Kod
  • Metoda 17 gc: oznaczona jako natywna i bez atrybutu Kod

wprowadź opis zdjęcia tutaj

W rzeczywistości logika kodowania znajduje się w odpowiednim pliku Runtime.c :

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  }

A te Ckodowanie jest kompilowany do libjava.so(Linux) lub libjava.dllpliku (Windows), znajduje się na JAVA_HOME/jmods/java.base.jmod/lib/libjava.so:

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

Odniesienie

Szczęśliwy
źródło