http://blog.houzhi.me/2016/03/19/java-signature-reflect-jni
在這段時間寫東西,必須要先吐槽一下找實習的杯具。找個實習不容易,沒經驗,各種跪。
一直都覺得在Java反射中,那些反射的方法調用都很有規律,每一個調用都需要相同的特性:函數對象(Method),函數參數,類對象。今天坐在電腦前又回憶了JNI的調用方式(C++調用Java),也需要相同的內容:函數ID(jmethodID),參數,類對象(jobject),JNIEnv。仔細一比較,其實兩者就是一樣的,都是Java方法簽名。
記得剛學Java的時候,也有特別將Java方法簽名,那時候就基本是記下了,但是根本沒想到Java方法簽名意味着什麼,現在終於是能深切體會一些了。這個簽名就表示了Java方法,相當於它的ID,適用於Java整個環境,能夠通過指定這些內容,形容一次函數調用。我們平時採用普通方式調用Java函數,其實也就是先描述了函數,參數,類對象。其實在Java層,我覺得可以理解爲隱含了一個線程描述(JVM)。在native裏面,就有個JNIEnv(線程本地變量)描述一個Java虛擬機環境。至於到了java的.class文件裏面也是一樣的包含了這些標誌。下面是截取了一段Constant poll中的內容,裏面指定了類StringBuilder,方法參數String,
#12 = Methodref #7.#55 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
下面是.class文件方法段裏面的stack代碼,
21: invokevirtual #12 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
只是感性的認識,如果把全部的.class 文件通過javap -verbose 的內容都貼上來,實在太囧了。對於invokevirtual命令可以參考這裏的http://book.51cto.com/art/200906/131732.htm。如果想要了解,需要對虛擬機指令的操作方式有所瞭解,那個東東跟彙編有點類似。
關於java方法簽名,官網上面有介紹java method signatures。Java的方法聲明具有下面幾個組件:
- 訪問標誌(public,private…)
- 返回類型
- 方法名
- 參數列表
- 異常表
- 方法體
但是Java方法中真正被判斷是否是同一個方法的簽名與上面是不一致的,就像我們熟知的方法重載一樣。正如method signatures 所說,它在內部真正具體標記意義的是方法名稱和參數列表,因爲這種都是在同一個類裏面講重載的,真正算起來應該還要加上具體的類方法,以及具體JVM線程。所以JNI和反射的調用其實就是指定了函數實際的標記:JVM,類對象,方法ID(Method,jmethodID),參數列表。
所以如果需要對各種方式的Java調用進行完全的認識,就需要熟記Java這幾種簽名標記的特性。如果在實際編碼過程中,想要去調用一個方法,那麼一定要獲取對應的對象,方法名,方法參數。如果是可能存在不同的虛擬機環境,那還得加上虛擬機環境的標記(類似JNIEnv)。當然C/C++的虛擬機中,由於C/C++中int,Object並沒有統一父對象,C/C++ JNI提供了針對不同的返回類型,對應不同的調用函數。
好好學習