package cn.itcast;
public calss TestNative {
public native void sayHello();
public static void main(String[] arg){
}
}```
2. 用javah.exe生成包含native方法的C/C++頭文件
javah -jni(默認)
javah cn.itcast.TestNative //由類名執行生成C/C++頭文件
生成的頭文件內容:JNIEXPORT void JNICALL Java_cn_itcast_TestNative_SayHello (JNIEnv*, jobject)
3. 參照生成的頭文件生成C/C++源文件
在VS下:Win32工程-->DLL-->空的工程-->結束
把生成的頭文件引入到C++工程中,從JDK/include和include/win32中
jni.h和jni_md.h文件,然后創建一個新的C++源文件
```java
#include
#include "cn_itcast_TestNative.h"
JNIEXPORT void JNICALL Java_cn_itcast_TestNative_sayHello
(JNIEnv* env, jobject obj){
count<
4. 返回Java寫Java調用dll代碼部分
在主函數中:
System.loadLibrary("nativeCode")//寫入你生成的dll文件名,但不要寫“.dll”java會自動識別Windows還是Linux系統
new TestNative().sayHello();
運行一下,結果:
Hello world
----
##使用JNI的兩個弊端
1. 使用JNI,這個Java Application就不跨平臺了,如果要移植到其他平臺那么native代碼就要重新編寫,編譯。
2. Java是強類型語言,C/C++不是,因此使用JNI要格外小心
**總之,盡量少用JNI**
本地代碼訪問Java代碼
* 在本地調用的C/C++函數中也可以反過來訪問Java程序中的類
* javah工具生成C/C++函數生命中,可以看到兩個參數
> JNI* env 實際上代表了Java環境,通過JNIEnv*指針,就可以對Java端代碼進行操作,例如:創建Java類的對象,調用Java對象的方法,獲取Java對象屬性等
* JNIEnv類中有很多函數可以用。
NewObject/NewString/New Array
Get/SetField
CallMethod /CallStaticMethod 等許多函數某個類型的變量
> jobject* obj 被定義為_jobject
* Java操作對象為引入操作,而C/C++中使用指針對對象操作
* jobject* obj 指向一個Java對象的引用,這個對象引用是Java中Native方法所對應的對象
<1>若native方法非靜態,它指向native方法所對應的實例
<2>若native方法靜態(static)那么它指向native所對應的class對象:Class.class
### Java類型在C/C++中的映射關系
| Java | 本地類型 | JNI定義的別名(jni.h中定義) |
| ------- |:------------------:| -------:|
| int | long | jint/jsize |
| long | _int64 | jlong |
| byte | signed char | jbyte |
| boolean | unsigned char | jboolen |
| char | signed short | jchar |
| short | short | jshort |
| float | float | jfloat |
| double | double | jdouble |
| Object | _jobject* | jobject |
### jclass的取得
typedef _jclass* jclass
為了使C/C++使用Java類,Jni.h頭文件中專門定義了jclass類型表示Java中的class類
JNIEnv類中有如下幾個簡單的函數可以取得jclass:
- jclass FindClass(const char * clsName);
- jclass GetObjectClass (jobject obj);
- jclass GetSuperClass (jclass obj);
Findclass會在classpath系統環境變量下尋找類
傳入完整的類名,注意包與包之間是'/'而不是'.'來分隔
如:jclass cls_string=env->FindClass("Java/lang/String")
C/C++訪問Java端代碼,一個常用的應用就是獲取類的屬性和調用類的方法,為了在C/C++中表示屬性和方法JNI在jni.h頭文件中定義了jfieldID,jmethodID分別代表Java端屬性和方法
我們在訪問或設置Java屬性時,必須先取得代表Java屬性的jfieldID,然后才可以在本地代碼進行Java屬性操作;同樣,需要使用Java端方法時,也是要取得代表該方法的jmethodID才能對Java方法調用。
使用JNIEnv的GetFieldID/GetMethodID GetStaticFieldID/GetStaticMethodID 來取得相應的jfieldID和jmethodID
* 方法原型:GetFieldID/GetStaticFieldID/GetMethodID/GetStaticMethodID(jclass clazz,const char* name,const char* sign)
如:env->GetMethodID(data_clazz,"","()V")
* Sign簽名,用來表示取得的屬性/方法的類型
| 類型 | 相應簽名 |
| ------- |:------------------:|
| boolean | Z |
| byte | B |
| char | C |
| short | S |
| int | I |
| long | L |
| float | F |
| double | D |
| void | V |
| object | L 用“/”分隔包的完整類名;如:Ljava/lang/String; |
| Array(數組) | [Sign 如[L [Ljava/lang/object; |
| Method | (Type)V 若指定“(I)V” 則取回 void function(int)的jmethodID
若指定“(D)V”則取回void function(double)的jmethodID|