探索JAVA知識的路上遇上了JNI
*前言:前幾天學習時打開了jdk原始碼包,看了集合框架的一些原始碼,想著深化學習下,可是不知道怎麼就打開了FileOpenInputStream的原始碼,看到了下面四個native方法(當然還有其它native方法):
private native void open0(String name) throws FileNotFoundException; private native int readBytes(byte b[], int off, int len) throws IOException; private native void close0() throws IOException;
於是有了一些聯想。聯絡到c中的下列函式:
FILE *fopen( const char * filename, const char * mode );
char *fgets( char *buf, int n, FILE *fp );
int fclose( FILE *fp );
可不是嘛,真像(真香警告!!哈哈),寫到這裡想著要不就把這三個本地方法給實現編寫個自己的FileInputStream,猜測也許可能分別呼叫這三個方法可能行不通呢,但學習可不就是這樣,不去試著搞搞,怎麼提升自己,嘿嘿。希望以後自己看到自己現在的學習狀態不會嘲笑自己吧。
在實現這條路上需要補全很多這方面的知識,JNI的API的熟悉,JNI資料型別與C++中資料型別轉換...
大前天和昨天都在實現native方法呼叫。中間一天佩女朋友了哈哈。在實現過程中當然中間遇到一些問題啦。遇到問題是好事,在解決問題中你可以獲得很多沒有遇到問題時的知識。
*JNI(java native interface) ,它提供了若干的API實現了Java和其他語言的通訊(主要是C&C++)
JNI使用的副作用:
1、程式不再跨平臺。要想跨平臺,必須在不同的系統環境下重新編譯本地語言部分。
2、程式不再是絕對安全的,原生代碼的不當使用可能導致整個程式崩潰。
這裡記錄下實現一個簡單的JNI列子:
1.編寫好例子HelloWorld.java
public class HelloWorld{ public native void sayHello(); static{ System.loadLibrary("hello"); //引用動態連結庫的名稱 } public static void main(String[] args){ new HelloWorld().sayHello(); } }
*System.loadLibrary("hello");在這裡宣告JNI的不再跨平臺,不同系統平臺下載入引用的動態連結庫不同
windows平臺下呼叫的動態連結庫為hello.dll
linux平臺下呼叫動態連結庫為hello.so
2.在編譯生成動態連結庫前,先編寫本地實現程式碼c/c++
1)在編寫c/c++程式碼前,在當前環境下編譯HelloWorld.java程式,使用使用工具javah將使用生成程式要使用的標頭檔案HelloWorld.h,執行命令( javah -jni HelloWorld),不同系統平臺下標頭檔案都一樣。
2)引用上面標頭檔案編寫實現程式碼HelloWorld.c
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL Java_HelloWorld_sayHello(JNIEnv *jbi, jobject obj){
printf("HelloWorld");
return;
}
3.生成動態連結庫
windows下可使用vc++(推薦),mingw或其他
錯誤資訊為64位的VM不能載入32位的dll(通過java -version檢視本機安裝VM為多少位的)
預設mingw編譯32位作業系統程式。
可下載mingw-w64配置後編譯為64位系統程式(hello.dll),
自己在編譯時系統內部報錯跳過該方法,使用了vc++生成64位的hello.dll,畢竟微軟家的系統和微軟家的vc++;
總結:不同位數的作業系統,執行著不同位數的VM,而VM只支援相同位數的程式時。不同平臺的複雜性,造就了跨平臺的重要性。
linux中使用系統自帶gcc編譯生成
-I大寫的i
gcc -I$JAVA_HOME/java/include -I$JAVA_HOME/java/include/linux HelloWorld.c -fPIC -shared -o hello.so
4.最後執行 java HelloWorld 得到輸出內容
。。。。。。。。。。後續實現文章開頭想要嘗試的,不是一時半夥完成的,堅持住。