Для чего нужно ключевое слово в Java?


476

Во время игры в эту головоломку (это Java-игра с ключевыми словами) я наткнулся на nativeключевое слово.

Для чего используется ключевое слово native в Java?


Ответы:


343

nativeКлючевое слово применяется к методу , чтобы указать , что метод реализован в нативном коде с помощью JNI (Java Native Interface).


3
Реальная реализация не должна использовать JNI. Некоторые методы JRE по своей природе обрабатываются JVM. На самом деле, даже не обязательно, чтобы реализация была на самом деле нативным кодом. Он просто «реализован на языке, отличном от языка программирования Java» .
Хольгер

444

Минимальный исполняемый пример

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

Скомпилируйте и запустите:

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

Вывод:

4

Протестировано на Ubuntu 14.04 AMD64. Также работал с Oracle JDK 1.8.0_45.

Пример на GitHub для вас, чтобы играть с.

Символы подчеркивания в именах пакетов / файлов Java должны быть экранированы _1в имени функции C, как указано в разделе: Вызов функций JNI в имени пакета Android, содержащем подчеркивание

интерпретация

native позволяет вам:

  • вызвать скомпилированную динамически загружаемую библиотеку (здесь написанную на C) с произвольным ассемблерным кодом из Java
  • и получить результаты обратно в Java

Это может быть использовано для:

  • писать более быстрый код в критической секции с лучшими инструкциями по сборке ЦП (не переносимых ЦП)
  • делать прямые системные вызовы (не переносимые ОС)

с компромиссом более низкой мобильности.

Вы также можете вызывать Java из C, но вы должны сначала создать JVM в C: Как вызывать функции Java из C ++?

Аналогичные нативные API расширения также присутствуют во многих других «языках ВМ» по тем же причинам, например, Python , Node.js , Ruby .

Android NDK

Концепция в этом контексте точно такая же, за исключением того, что для ее настройки необходимо использовать шаблон Android.

Официальный репозиторий NDK содержит «канонические» примеры, такие как приложение hello-jni:

В unzipслучае .apkс NDK на Android O вы можете увидеть предварительно скомпилированный .soкод, соответствующий нативному коду lib/arm64-v8a/libnative-lib.so.

Подтверждение TODO: кроме того, file /data/app/com.android.appname-*/oat/arm64/base.odexговорит, что это общая библиотека, которая, как мне кажется, является предварительно скомпилированным AOT .dex, соответствующим файлам Java в ART, см. Также: Что такое файлы ODEX в Android? Так может быть, Java на самом деле также запускается через nativeинтерфейс?

Пример в OpenJDK 8

Давайте найдем найти, где Object#cloneопределено в jdk8u60-b27.

Сделаем вывод, что это реализовано с помощью nativeвызова.

Сначала мы находим:

find . -name Object.java

что приводит нас к jdk / src / share / classes / java / lang / Object.java # l212 :

protected native Object clone() throws CloneNotSupportedException;

Теперь самое сложное - найти место, где клон находится среди всего косвенного. Вопрос, который мне помог, был:

find . -iname object.c

который найдет файлы C или C ++, которые могут реализовать нативные методы Object. Это приводит нас к 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]));
}

что приводит нас к JVM_Cloneсимволу:

grep -R JVM_Clone

что приводит нас к точке доступа / src / share / vm / prims / jvm.cpp # l580 :

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

Развернув кучу макросов, мы приходим к выводу, что это точка определения.


1
Отличный ответ. Просто сноска: для static nativeметода Java второй параметр функции C ++ имеет тип, jclassа не тип jobject.
SR_

@SR_ спасибо за информацию. Была ли ошибка в моем ответе, или это просто дополнительная информация?
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

2
@Ciro - это дополнительная информация для тех, кто начинает с вашего примера (ответом может быть около 300 на SO). У меня была функция с неправильной подписью, вызванная с беспорядком в стеке, без сообщений об ошибках (во время компиляции, компоновки или выполнения). Поэтому я считаю важным упомянуть, чтобы быть осторожным на этом этапе.
SR_

420

Он отмечает метод, который будет реализован на других языках, а не на Java. Он работает вместе с JNI (Java Native Interface).

В прошлом для написания критических разделов, касающихся производительности, использовались собственные методы, но с ускорением работы Java это стало менее распространенным явлением. Родные методы в настоящее время необходимы, когда

  • Вам нужно вызвать библиотеку из Java, написанную на другом языке.

  • Вам необходимо получить доступ к системным или аппаратным ресурсам, доступным только с другого языка (обычно C). На самом деле, многие системные функции, которые взаимодействуют с реальным компьютером (например, с дисковым и сетевым вводом-выводом), могут делать это только потому, что они вызывают собственный код.

См. Также Спецификация собственного интерфейса Java


3
Насколько я понимаю, я пишу System.currentTimeMillis () (который является родным) в Java-файле, и затем, чтобы это работало, JNI будет вызывать библиотеки или некоторые функции, написанные на C или C ++ или ассемблере, а затем возвращать некоторое значение обратно в мой Java-код , пример: здесь метод currentTimeMillis вызывает собственный код с помощью JNI, и этот собственный код взаимодействует с системным ресурсом ex: таймером, установленным на материнской плате и таким образом получающим возвращаемое значение (системное время). поправьте меня, пожалуйста?
MKod

4
Методы @MKod like currentTimeMillisявляются частью JDK и снабжены комментариями, nativeпотому что реализация находится в самом исходном коде JDK. Маловероятно, что реализация использует ассемблер; он, вероятно, вызывает метод API операционной системы, над которой работает JVM. Например, в Windows это может вызвать метод DLL GetSystemTimeв kernel32.dll. На другой ОС у него будет другая реализация. Однако, когда вы используете nativeметод, который вы пишете (в отличие от метода JDK), вы должны предоставить реализацию, используя JNI.
Адам Берли

Это утверждение является важным для ключевого слова Native ... «Вам необходимо получить доступ к системным или аппаратным ресурсам, доступным только на другом языке (обычно C)».
atiqkhaled

@Kidburla Могу я спросить, что вы подразумеваете под "реализацией в самом исходном коде JDK"? currentTimeMillisпомечен как нативный в, java.lang.Systemтак что он использует JNI, не так ли?
flow2k

1
@ flow2k да, то, что вы сказали, вероятно, правда, я не уверен, почему я сказал это в своем комментарии (более 2 лет назад)
Адам Берли

59

Прямо из в спецификации языка Java :

Метод, который nativeреализован в зависимом от платформы коде, обычно написанном на другом языке программирования, таком как C, C ++, FORTRAN или ассемблер. Тело nativeметода задается только точкой с запятой, что указывает на то, что реализация опущена, а не блок.


19

Как ответил SLaks, nativeключевое слово для вызова нативного кода.

Он также используется GWT для реализации методов javascript.


13

функции, которые реализуют нативный код, объявляются нативными.

Собственный интерфейс Java (JNI) - это среда программирования, которая позволяет коду Java, выполняющемуся на виртуальной машине Java (JVM), вызывать и вызываться собственными приложениями (программами, специфичными для платформы оборудования и операционной системы) и библиотеками, написанными на другие языки, такие как C, C ++ и ассемблер.

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


8

NATIVE - это не модификатор доступа. Он может применяться только к МЕТОДУ. Это указывает на платформо-зависимую реализацию метода или кода.


6

native - это ключевое слово в java, которое используется для создания неосуществленной структуры (метода) как абстрактной, но это будет зависеть от платформы, такой как собственный код, и выполняться из собственного стека, а не из стека java.


6
  • native является ключевым словом в Java, оно указывает на платформу зависит.
  • nativeметоды являются интерфейсом между Java ( JNI ) и другими языками программирования.

3

Ява nativeМетод обеспечивает механизм для кода Java для вызова собственного кода ОС либо по функциональным соображениям, либо по соображениям производительности.

Пример:

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

В соответствующем Runtime.classфайле в OpenJDK, расположенном в JAVA_HOME/jmods/java.base.jmod/classes/java/lang/Runtime.class, содержатся эти методы и помечены их с помощью ACC_NATIVE( 0x0100), и эти методы не содержат атрибута Code , что означает, что эти методы не имеют никакой реальной логики кодирования в Runtime.classфайле:

  • Метод 13 availableProcessors: помечены как родные и без атрибута кода
  • Метод 14 freeMemory: помечены как родные и без атрибута кода
  • Метод 15 totalMemory: помеченный как родной и без атрибута кода
  • Метод 16 maxMemory: помечены как родные и без атрибута кода
  • Метод 17 gc: помечены как родные и без атрибута кода

введите описание изображения здесь

Фактически логика кодирования находится в соответствующем файле 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  }

И эти Cкодировки скомпилированы в libjava.so(Linux) или libjava.dll(Windows) файл, расположенный по адресу JAVA_HOME/jmods/java.base.jmod/lib/libjava.so:

введите описание изображения здесь

введите описание изображения здесь

Ссылка

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.