1. 程式人生 > >JNI 之c/c++和Java互動,呼叫java成員

JNI 之c/c++和Java互動,呼叫java成員

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 類中的成員的簽名
da

c/c++有很多方法是沒有的但Java有的,如果c/c++自己實現起來很不方便,不如呼叫java現有的,這也是面向物件思想體現。