Loading AI tools
来自维基百科,自由的百科全书
JNI (Java Native Interface,Java本地介面)是一種編程框架,使得Java虛擬機器中的Java程式可以呼叫本地應用/或庫,也可以被其他程式呼叫。 本地程式一般是用其它語言(C、C++或匯編語言等)編寫的,並且被編譯為基於本機硬件和作業系統的程式。[1]
此條目翻譯質素不佳。 (2014年11月1日) |
有些事情Java無法處理時,JNI允許程式設計師用其他程式語言來解決,例如,Java標準庫不支援的平台相關功能或者程式庫。也用於改造已存在的用其它語言寫的程式,供Java程式呼叫。許多基於JNI的標準庫提供了很多功能給程式設計師使用,例如檔案I/O、音頻相關的功能。當然,也有各種高效能的程式,以及平台相關的API實現,允許所有Java應用程式安全並且平台獨立地使用這些功能。
JNI框架允許Native方法呼叫Java對象,就像Java程式訪問Native對象一樣方便。Native方法可以建立Java對象,讀取這些對象,並呼叫Java對象執行某些方法。當然Native方法也可以讀取由Java程式自身建立的對象,並呼叫這些對象的方法。
在JNI框架,native方法一般在單獨的.c或.cpp檔案中實現。當JVM呼叫這些函數,就傳遞一個JNIEnv
指標,一個jobject
的指標,任何在Java方法中聲明的Java參數。一個JNI函數看起來類似這樣:
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj)
{
/*Implement Native Method Here*/
}
env
指向一個結構包含了到JVM的介面,包含了所有必須的函數與JVM互動、訪問Java對象。例如,把本地陣列轉換為Java陣列的JNI函數,把本地字串轉換為Java字串的JNI函數,實例化對象,投擲異常等。基本上,Java程式可以做的任何事情都可以用JNIEnv
做到,雖然相當不容易。
例如,下面代碼把Java字串轉化為本地字串:
//C++ code
extern "C"
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
//Get the native string from javaString
const char *nativeString = env->GetStringUTFChars(javaString, 0);
//Do something with the nativeString
//DON'T FORGET THIS LINE!!!
env->ReleaseStringUTFChars(javaString, nativeString);
}
/*C code*/
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
/*Get the native string from javaString*/
const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);
/*Do something with the nativeString*/
/*DON'T FORGET THIS LINE!!!*/
(*env)->ReleaseStringUTFChars(env, javaString, nativeString);
}
/*Objective-C code*/
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
/*DON'T FORGET THIS LINE!!!*/
JNF_COCOA_ENTER(env);
/*Get the native string from javaString*/
NSString* nativeString = JNFJavaToNSString(env, javaString);
/*Do something with the nativeString*/
/*DON'T FORGET THIS LINE!!!*/
JNF_COCOA_EXIT(env);
}
本地資料類型與Java資料類型可以互相對映。對於複合資料類型,如對象,陣列,字串,就必須用JNIEnv
中的方法來顯示地轉換。
第2個參數obj參照到一個Java對象,在其中聲明了本地方法。
下表是Java (JNI)與本地代碼之間的資料類型對映:
本地類型 | Java語言的類型 | 描述 | 類型簽章(signature) |
---|---|---|---|
unsigned char | jboolean | unsigned 8 bits | Z |
signed char | jbyte | signed 8 bits | B |
unsigned short | jchar | unsigned 16 bits | C |
short | jshort | signed 16 bits | S |
long | jint | signed 32 bits | I |
long long |
jlong | signed 64 bits | J |
float | jfloat | 32 bits | F |
double | jdouble | 64 bits | D |
void | V |
簽章"L fully-qualified-class ;"
是由該名字指明的類。例如,簽章"Ljava/lang/String;"
是類java.lang.String
。帶字首[
的簽章表示該類型的陣列,如[I
表示整型陣列。void
簽章使用V
代碼。
這些類型是可以互換的,如jint
也可使用 int
,不需任何類型轉換。
但是,Java字串、陣列與本地字串、陣列是不同的。如果在使用char *
代替了jstring
,程式可能會導致JVM崩潰。
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString) {
// printf("%s", javaString); // INCORRECT: Could crash VM!
// Correct way: Create and release native string from Java string
const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);
printf("%s", nativeString);
(*env)->ReleaseStringUTFChars(env, javaString, nativeString);
}
這種情況也適用於Java陣列。下例對陣列元素求和。
JNIEXPORT jint JNICALL Java_IntArray_sumArray
(JNIEnv *env, jobject obj, jintArray arr) {
jint buf[10];
jint i, sum = 0;
// This line is necessary, since Java arrays are not guaranteed
// to have a continuous memory layout like C arrays.
env->GetIntArrayRegion(arr, 0, 10, buf);
for (i = 0; i < 10; i++) {
sum += buf[i];
}
return sum;
}
JNI環境指標(JNIEnv*)作為每個對映為Java方法的本地幔數的第一個參數,使得本地幔數可以與JNI環境互動。這個JNI介面指標可以儲存,但僅在當前線程中有效。其它線程必須首先呼叫AttachCurrentThread()把自身附加到虛擬機器以獲得JNI介面指標。一旦附加,本地線程執行就類似執行本地幔數的正常Java線程。本地線程直到執行DetachCurrentThread()把自身脫離虛擬機器。[5]
把當前線程附加到虛擬機器並取得JNI介面指標:
JNIEnv *env; (*g_vm)->AttachCurrentThread (g_vm, (void **) &env, NULL);
當前線程脫離虛擬機器:
(*g_vm)->DetachCurrentThread (g_vm);
本地代碼不僅可以與Java互動,也可以在Java Canvas
繪圖,使用Java AWT Native Interface。
Microsoft實現的Java虛擬機器——Visual J++的類似的訪問本地Windows代碼的機制Raw Native Interface(RNI)。
make.sh
#!/bin/sh
# openbsd 4.9
# gcc 4.2.1
# openjdk 1.7.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
javac HelloWorld.java
javah HelloWorld
gcc -shared libHelloWorld.c -o libHelloWorld.so
java HelloWorld
build.bat
:: Microsoft Visual Studio 2012 Visual C++ compiler
SET VC="C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC"
:: Microsoft Windows SDK for Windows 7 and .NET Framework 4
SET MSDK="C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A"
:: Java 1.7.0 update 21
SET JAVA_HOME="C:\Program Files (x86)\Java\jdk1.7.0_21"
call %VC%\vcvarsall.bat
javac HelloWorld.java
javah HelloWorld
%VC%\bin\cl /I%JAVA_HOME%\include /I%JAVA_HOME%\include\win32 /I%VC%\include /I%VC%\lib /I%MSDK%\Lib libHelloWorld.c /FelibHelloWorld.dll /LD
java HelloWorld
HelloWorld.java
class HelloWorld
{
private native void print();
public static void main(String[] args)
{
new HelloWorld().print();
}
static{
System.loadLibrary("HelloWorld");
}
}
HelloWorld.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: print
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_print
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
libHelloWorld.c
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
printf("Hello World!\n");
return;
}
Invocation:
$ chmod +x make.sh
$ ./make.sh
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.