JNI 之c/c++和Java互動,呼叫java成員
阿新 • • 發佈:2018-11-05
public class JniTest2 {
//c訪問非靜態成員
public String testField="hello...";
//c修改java靜態成員
public static int time=78;
//c訪問java 方法
public native void invokeJavaMethod();
//c修改java 靜態成員
public native void modifyStaField();
public native static String getProgress();
public native String getStringFromC();
public static void main(String[] args) {
// TODO Auto-generated method stub
String progress=getProgress();
System.out.println("test=from c="+progress);
JniTest2 t=new JniTest2();
System.out.println("test c before=="+t.testField);
String result=t.getStringFromC();
System.out .println("test c after=="+result);
System.out.println("===============靜態成員修改==============");
System.out.println("test=c beforestatic="+time);
t.modifyStaField();
System.out.println("test=c after static="+time);
System.out.println("===============呼叫java方法==============" );
t.invokeJavaMethod();
}
static {
//載入x64 .dll靜態庫
System.loadLibrary("JNIDateType");
}
public int generateRandom(int seed) {
System.out.println("test=java 方法被C呼叫了=");
return new Random().nextInt(seed);
}
}
下面是c/c++訪問java 成員和方法
#define _CRT_SECURE_NO_WARNINGS
#include "jni_data_test_JniTest2.h"
#include<string.h>
//c返回java 層資料
JNIEXPORT jstring JNICALL Java_jni_1data_1test_JniTest2_getProgress
(JNIEnv *Env, jclass jcls){
//Java函式在c層實現
char *progress = "95";
return (*Env)->NewStringUTF(Env,progress);
};
//c重寫實現java方法
JNIEXPORT jstring JNICALL Java_jni_1data_1test_JniTest2_getStringFromC
(JNIEnv *Env, jobject jobj){
//得到java 發射類
jclass jobjclass= (*Env)->GetObjectClass(Env,jobj);
//通過反射得到java 成員,注意最後一個引數是資料型別簽名“L+類名(中間斜槓)”
jfieldID jfield = (*Env)->GetFieldID(Env, jobjclass, "testField", "Ljava/lang/String;");
//獲取當前成員屬性值
jstring jfieldvalue = (*Env)->GetObjectField(Env,jobj,jfield);
//注意:c無法修改jstring,進行轉換char*,最後一個引數是否複製
char *fieldValue = (*Env)->GetStringUTFChars(Env, jfieldvalue, NULL);
strcat(fieldValue,"what the fuck!");
//char * 轉成 jstring 返回
jstring result =(*Env)->NewStringUTF(Env,fieldValue);
//修改java的成員值
(*Env)->SetObjectField(Env,jobj,jfield,result);
return result;
};
//c 呼叫java 方法
JNIEXPORT void JNICALL Java_jni_1data_1test_JniTest2_invokeJavaMethod
(JNIEnv *Env, jobject jobj){
//反射java類
jclass javaclass=(*Env)->GetObjectClass(Env,jobj);
//獲取方法id,方法簽名 java工程bin目錄 javap -s -p java全類名
jmethodID methodId=(*Env)->GetMethodID(Env,javaclass,"generateRandom","(I)I");
//呼叫方法
jint value=(*Env)->CallIntMethod(Env,jobj,methodId,89);
printf("c呼叫java方法結果==%d==\n",value);
};
//c 修改java靜態成員
JNIEXPORT void JNICALL Java_jni_1data_1test_JniTest2_modifyStaField
(JNIEnv *Env, jobject jobj){
jclass javaclz= (*Env)->GetObjectClass(Env,jobj);
//注意成員簽名
jfieldID staFieldId=(*Env)->GetStaticFieldID(Env,javaclz,"time","I");
//jint 是long型別,可強轉
jint fieldValue= (*Env)->GetStaticIntField(Env,javaclz,staFieldId);
fieldValue += 15;
//修改完成設定static 成員
(*Env)->SetStaticIntField(Env,javaclz,staFieldId,fieldValue);
};
執行效果如下,工作空間GBK和UTF8不協調亂碼
總結:其中最值得注意的是,獲取java 類裡面所有成員簽名的命令方式
//簽名,進入 java工程bin目錄 javap -s -p java全類名
見如下圖中標紅的,就是java 類中的成員的簽名
c/c++有很多方法是沒有的但Java有的,如果c/c++自己實現起來很不方便,不如呼叫java現有的,這也是面向物件思想體現。