本地方法怎麼對映Java層的資料型別

超人汪小建發表於2019-02-26

前言

Java 語言上定義了不同的資料型別,比如有基礎型別intdouble等等,還有所有類的父類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->jintObject->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;
複製程式碼

CPP的空類

上面的引用型別定義為空類,這裡瞭解下C++的空類,通常我們要定義一個空類可以如下兩種方式,

class Empty{}
複製程式碼
struct Empty{}
複製程式碼

經過上述定義後的空類,它的大小為1,但是一個空類啥都沒有的話它有什麼用呢?其實它可以用來區分不同的物件,空類定義的不同物件擁有不同的地址,使用new操作出來的物件也有不同的指標,而且空類也能區分不同的類別。

指標轉換

所以有了這些型別對映後我們是怎麼聯絡起來使用的呢?其實很簡單,答案就是進行指標轉換,前面提到過 Java 層的物件在 JVM 中是有一定的資料結構的,即用 oop 來表示物件指標,那麼 jobject 可以作如下轉換,其中 handle 即為 jobject 型別。

oop result = *reinterpret_cast<oop*>(handle);
複製程式碼

轉換成 oop 後要進一步處理就很方便了,比如想要獲取一些類相關的後設資料時可以使用其中的 klass 來獲取。

總結

以上,Java 層定義的型別在本地方法有著與之相對應的資料型別,而且 Java 層原始碼被編譯為位元組碼後儲存了本地方法引數對應的型別,JVM 執行時可以根據不同的型別轉換成本地方法對應的型別,而本地方法定義的型別都為空類,主要作用是用來繫結物件,並且可以區分物件型別,在必要時刻通過指標轉換即可訪問物件或類後設資料。

-------------推薦閱讀------------

我的2017文章彙總——機器學習篇

我的2017文章彙總——Java及中介軟體

我的2017文章彙總——深度學習篇

我的2017文章彙總——JDK原始碼篇

我的2017文章彙總——自然語言處理篇

我的2017文章彙總——Java併發篇

------------------廣告時間----------------

知識星球:遠洋號

公眾號的選單已分為“分散式”、“機器學習”、“深度學習”、“NLP”、“Java深度”、“Java併發核心”、“JDK原始碼”、“Tomcat核心”等,可能有一款適合你的胃口。

為什麼寫《Tomcat核心設計剖析》

歡迎關注:

這裡寫圖片描述

相關文章