2009-02-17 1 views

ответ

34

Эти методы являются либо Intrinsic, либо написаны вне Java в «родном» коде, то есть конкретном для данного компьютера.

Те, что вы упоминаете являются искробезопасности и часть JDK, но вы также можете написать собственные методы самостоятельно, используя Java Native Interface (JNI). Обычно это будет использовать C для написания методов, но многие другие языки, такие как python, позволяют вам легко писать методы таким образом. Код написан таким образом либо для производительности, либо потому, что ему необходимо получить доступ к инфраструктуре, специфичной для платформы, которая не может быть выполнена в простой Java.

В случае hashcode() это реализовано JVM. Это связано с тем, что часто хэш-код будет связан с чем-то, что знает только JVM. На ранних JVM это было связано с расположением объекта в памяти - на других JVM объект может перемещаться в памяти, и поэтому может быть использована более сложная (но все же очень быстрая) схема.

+6

if hashcode() реализован JVM только для чего требуется, чтобы он был * native *? Что именно вы подразумеваете под * внутренним * здесь? – Geek

11

Собственные методы реализованы в основном в C и скомпилированы в собственный код, который запускается непосредственно на машине. Это отличается от обычных методов, которые реализованы в Java и скомпилированы в байт-код Java, который выполняется виртуальной машиной Java (JVM).

Чтобы связать эти методы с Java, вам необходимо использовать Java Native Interface (JNI).

Исходный код в основном необходим для доступа к материалам низкого уровня. В случае hashCode это адрес объекта в памяти. Мое предположение для clone заключается в том, что он копирует необработанную память из объекта-объекта в клонированный. Другие использования собственного кода предназначены для доступа к функциям ОС или аппаратным средствам.

Недостаток использования собственного кода заключается в том, что вы потеряете безопасность JVM, то есть ваша программа может потерпеть крах или иметь дыры в безопасности из-за ошибок в собственном коде.

17

Большинство собственных методов реализованы с использованием JNI, как указано в других ответах.

Однако критически важные для производительности методы, такие как Object.hashCode, обычно реализуются как внутренние. Когда код байта скомпилирован в машинный код, компилятор Java распознает вызов метода и строит соответствующий код напрямую. Очевидно, это будет намного быстрее, чем через JNI для тривиального метода.

Многие люди утверждают, что Object.hashCode вернет адрес представления объекта в памяти. В современных реализациях объекты фактически перемещаются в памяти. Вместо этого область заголовка объекта используется для хранения значения, которое может быть лениво выведено из адреса памяти в то время, когда сначала запрашивается значение.

+2

Для более подробной информации [visit] (http://stackoverflow.com/a/13860488/390695) –

10

Что это за туземцы и как эти методы работают?

Минимальный пример, чтобы сделать вещи яснее:

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.

Example on GitHub для вас, чтобы играть.

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

Это позволяет:

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

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

  • написать быстрый код на критический раздел с инструкциями лучше CPU сборки (не CPU переносными)
  • делают прямые системные вызовы (не OS портативный)

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

Это также возможно для вас назвать Java от C, но вы должны сначала создать JVM в C: How to call Java functions from C++?

Пример в OpenJDK 8

Давайте найдем найти, где 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 или 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 

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

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

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