Если мы посмотрим на класс Java Object, мы найдем некоторые из таких методов, как:
public native int hashCode()
protected native Object clone()
Что это за туземцы и как эти методы работают?
Если мы посмотрим на класс Java Object, мы найдем некоторые из таких методов, как:
public native int hashCode()
protected native Object clone()
Что это за туземцы и как эти методы работают?
Эти методы являются либо внутренними, либо написанными за пределами Java в "родном" коде, то есть конкретным для данного компьютера.
Те, которые вы упомянули, являются Intrinsic и частью JDK, но вы также можете сами писать собственные методы, используя Java Native Interface (JNI). Обычно это будет использовать C для написания методов, но многие другие языки, такие как python, позволяют вам легко писать методы таким образом. Код написан таким образом либо для производительности, либо потому, что ему нужно получить доступ к инфраструктуре, специфичной для платформы, которая не может быть выполнена в простой Java.
В случае hashcode()
это реализуется JVM. Это связано с тем, что часто хэш-код будет связан с чем-то, что знает только JVM. На ранних JVM это было связано с расположением объекта в памяти - на других JVM, объект может перемещаться в памяти, и поэтому может быть использована более сложная (но все же очень быстрая) схема.
Большинство собственных методов реализованы с использованием JNI, как указано в других ответах.
Однако критически важные для производительности методы, такие как Object.hashCode
, обычно реализуются как внутренние. Когда код байта скомпилирован в машинный код, компилятор Java распознает вызов метода и строит соответствующий код напрямую. Очевидно, это будет намного быстрее, чем через JNI для тривиального метода.
Многие утверждают, что Object.hashCode
вернет адрес представления объекта в памяти. В современных реализациях объекты фактически перемещаются в памяти. Вместо этого область заголовка объекта используется для хранения значения, которое может быть лениво выведено из адреса памяти в момент, когда сначала запрашивается значение.
Нативные методы реализованы в основном в C и скомпилированы в собственный код, который запускается непосредственно на машине. Это контрастирует с обычными методами, которые реализованы в Java и скомпилированы в байт-код Java, который выполняется виртуальной машиной Java (JVM).
Чтобы взаимодействовать с этими методами с Java, вам необходимо использовать Java Native Interface (JNI).
Исходный код в основном необходим для доступа к материалам низкого уровня. В случае hashCode это адрес объекта в памяти. Мое предположение для clone заключается в том, что он копирует необработанную память из объекта-объекта в клонированный. Другие использования собственного кода предназначены для доступа к функциям ОС или аппаратным средствам.
Недостаток использования собственного кода заключается в том, что вы теряете безопасность и безопасность JVM, то есть ваша программа может потерпеть крах или иметь дыры в безопасности из-за ошибок в собственном коде.
Что это за туземцы и как эти методы работают?
Минимальный пример, чтобы сделать более понятным:
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. Также работал с Oracle JDK 1.8.0_45.
Пример для GitHub для вас.
Интерпретация
Он позволяет:
Это можно использовать для:
с компромиссом более низкой переносимости.
Вы также можете вызвать Java из C, но сначала вы должны создать JVM в C: Как вызвать функции Java из С++?
Пример в OpenJDK 8
Найдите find, где Object#clone
определено в jdk8u60-b27.
Сначала найдем:
find . -name Object.java
что приводит нас к jdk/src/share/classes/java/lang/Object.java # l212:
protected native Object clone() throws CloneNotSupportedException;
Теперь наступает сложная часть, которая находит, где клон находится во всех направлениях. Запрос, который помог мне, заключался в следующем:
find . -iname object.c
который мог бы найти файлы C или С++, которые могли бы использовать собственные методы Object. Это приводит нас к jdk/share/native/java/lang/Object.С# 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
что приводит нас к hotspot/src/share/vm/prims/jvm.cpp # l580:
JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
JVMWrapper("JVM_Clone");
После расширения кучи макросов мы приходим к выводу, что это точка определения.
Нативные методы в Java реализованы с использованием Java Native Interface, известного как JNI.