Java 語言上定義了不同的數據類型,比如有基礎類型int、double等等,還有所有類的父類Object等,這些都是Java 層面的類型,而使用本地方法的處理過程需要有它們對應的類型。
Java 層編寫的本地方法,被編譯器編譯為字節碼,字節碼將按照規範將不同類型的參數給記錄到class 文件中,比如B 表示byte、I 表示int、J 表示long 等等。那麼一個如下的本地方法,被記錄為(Ljava/lang/Object;II)V。
public static native void test(Object o, int i, int i2);
上述對應的方法被註冊JVM中,當執行到調用本地方法時則會按照類型映射轉換成本地數據類型,比如int->jint和Object->jobject。這裡其實int 和jint 在C++ 中是一樣的,只是用typedef 定義了另外一個名稱而已,而jobject 是一個指針,執行引擎在執行Java 層邏輯時生成了Object 對象,它在JVM 層有專門的數據結構,這裡的jobject 就是指向這個結構的指針,在需要使用時可以強制轉換成JVM 層的數據結構,然後即可對其進行操作。另外,JVM 中用oop 來表示對象指針。
| Java Type | Native Type | value |
|---|---|---|
| boolean | jboolean | true或false |
| byte | jbyte | -128~127 |
| short | jshort | -pow(2,15)~pow(2,15)-1 |
| int | jint | -pow(2,31)~pow(2,31)-1 |
| long | jlong | -pow(2,63)~pow(2,63)-1 |
| float | jfloat | IEEE754標准單精度浮點數 |
| double | jdouble | IEEE754標準雙精度浮點數 |
| char | jchar | 16位不帶符號,Unicode字符 |
除了基礎的類型映射外,Java 層其他對像類型為引用類型,那麼本地方法對應的是jobject 類型,另外,它還會派生出經常用的一些子類,比如jstring、jclass 等等,具體如下,
class _jobject {};class _jclass : public _jobject {};class _jthrowable : public _jobject {};class _jstring : public _jobject {};class _jarray : public _jobject {};class _jbooleanArray : public _jarray {};class _jbyteArray : public _jarray {};class _jcharArray : public _jarray {};class _jshortArray : public _jarray {};class _jintArray : public _jarray {};class _jlongArray : public _jarray {};class _jfloatArray : public _jarray {};class _jdoubleArray : public _jarray {};class _jobjectArray : public _jarray {};可以看到定義了_jobject類,該類為空類,而其他的類包括_jclass _jthrowable _jstring _jarray都是繼承_jobject類。此外,數組類型還派生出了9個子類,分別對應基礎類型數組和引用類型數組。
前面定義完類後再定義指針別名,這裡的就是本地方法的類型了。另外,這些都是C++ 的定義,如果是C 編譯器則會使用struct 來定義_jobject,而非class。
typedef _jobject *jobject;typedef _jclass *jclass;typedef _jthrowable *jthrowable;typedef _jstring *jstring;typedef _jarray *jarray;typedef _jbooleanArray *jbooleanArray;typedef _jbyteArray *jbyteArray;typedef _jcharArray *jcharArray;typedef _jshortArray *jshortArray;typedef _jintArray *jintArray;typedef _jlongArray *jlongArray;typedef _jfloatArray *jfloatArray;typedef _jdoubleArray *jdoubleArray;typedef _jobjectArray *jobjectArray;
上面的引用類型定義為空類,這裡了解下C++的空類,通常我們要定義一個空類可以如下兩種方式,
class Empty{}struct Empty{}經過上述定義後的空類,它的大小為1,但是一個空類啥都沒有的話它有什麼用呢?其實它可以用來區分不同的對象,空類定義的不同對象擁有不同的地址,使用new操作出來的對像也有不同的指針,而且空類也能區分不同的類別。
所以有了這些類型映射後我們是怎麼聯繫起來使用的呢?其實很簡單,答案就是進行指針轉換,前面提到過Java 層的對像在JVM 中是有一定的數據結構的,即用oop 來表示對象指針,那麼jobject 可以作如下轉換,其中handle 即為jobject 類型。
oop result = *reinterpret_cast<oop*>(handle);
轉換成oop 後要進一步處理就很方便了,比如想要獲取一些類相關的元數據時可以使用其中的klass 來獲取。
以上,Java 層定義的類型在本地方法有著與之相對應的數據類型,而且Java 層源碼被編譯為字節碼後保存了本地方法參數對應的類型,JVM 執行時可以根據不同的類型轉換成本地方法對應的類型,而本地方法定義的類型都為空類,主要作用是用來綁定對象,並且可以區分對像類型,在必要時刻通過指針轉換即可訪問對像或類元數據。