2009-02-17 44 views
33

如果我們看一下Java對象類,那麼,我們可以找到一些像的方法:Java中的本地實現是什麼?

public native int hashCode() 
protected native Object clone() 

這些是什麼當地人和如何做這些方法的工作?

回答

34

這些方法要麼是固有的要麼寫在外部Java中的「本地」代碼,即特定於給定機器。

您提到的是固有的和JDK的一部分,但您也可以使用Java Native Interface(JNI)自己編寫本機方法。這通常使用C來編寫方法,但是很多其他語言(如python)允許您以相當簡單的方式編寫方法。代碼是以這種方式編寫的,無論是爲了性能,還是因爲它需要訪問平臺特定的基礎結構,而這些基礎結構不能用普通的java來完成。

hashcode()的情況下,這由JVM實現。這是因爲散列碼通常只與JVM知道的東西有關。在早期的JVM上,這與對象在內存中的位置有關 - 在其他JVM上,對象可能在內存中移動,因此可能會使用更復雜(但仍然非常快)的方案。

+6

如果hashcode()僅由JVM實現,爲什麼它需要* native *?你究竟在這裏指的是什麼? – Geek 2013-08-31 11:25:46

11

本機方法主要以C語言實現,並編譯爲直接在機器上運行的本機代碼。 這與普通方法相反,普通方法在Java中實現並編譯爲由Java虛擬機(JVM)執行的Java字節代碼。

要從Java接口到這些方法,您需要使用Java Native Interface (JNI)

本機代碼主要用於訪問低級別的東西。在hashCode的情況下,這是內存中對象的地址。我對克隆的猜測是它將原始內存從給定對象複製到克隆的對象。本地代碼的其他用途是訪問操作系統功能或硬件。

使用本機代碼的缺點是您失去了JVM的安全性,即由於本機代碼中的錯誤,您的程序可能會崩潰或存在安全漏洞。

17

大多數本地方法都是使用JNI實現的,如其他答案中所述。

但是,諸如Object.hashCode等性能關鍵方法通常作爲內在函數實現。當字節代碼被編譯爲機器代碼時,Java編譯器會識別方法調用並直接對適當的代碼進行內聯。這顯然比通過JNI處理一個簡單的方法要快得多。

很多人會聲稱Object.hashCode會返回內存中對象表示的地址。在現代實現中,對象實際上在內存中移動相反,對象頭部的一個區域用於存儲該值,該值可能是在第一次請求該值時從內存地址延遲派生的。

+2

欲瞭解更多詳情[請訪問](http://stackoverflow.com/a/13860488/390695) – 2012-12-13 13:21:40

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移植)

低便攜性的權衡。

也可以爲你從C調用Java,但你必須在C首先創建一個JVM:在OpenJDK的8

How to call Java functions from C++?

例子讓我們找到尋找到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 

哪些可以找到可能實現Object的本機方法的C或C++文件。它使我們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"); 

擴大了一堆宏之後,我們來得出這是定義的結論。