上一節中我們學習了JNI的開發流程,這一節我們學習JNI的資料型別。
關於資料型別的對映,大家可以參考這篇文章 JNI學習積累之二 ---- 資料型別對映、域描述符說明
這裡直接拿取了文章資料型別的列表
JAVA基本資料型別,可以直接使用,不需要轉換。其對映關係:Java型別->JNI型別->C型別
Java基本資料型別與JNI資料型別的對映關係:
上面的列表展示出來就是java的基本資料型別對應JNI的資料型別。
除了基本資料型別,還有JAVA的引用型別(物件),引用資料型別需要轉換後才能使用。
瞭解native函式
每個native函式,都至少有兩個引數(JNIEnv*,jclass或者jobject) 1)當native方法為靜態方法時:jclass 代表native方法所屬類的class物件(XX.class)
2)當native方法為非靜態方法時:jobject 代表native方法所屬的物件
public class Test {
public native static String getStringFromC();
public native String getString2FromC(int i);
public static void main(String[] args) {
// TODO Auto-generated method stub
String text = getStringFromC();
System.out.println(text);
//訪問非靜態方法
Test t = new Test();
System.out.println(t.getString2FromC(500));
}
//載入動態庫
static {
System.loadLibrary("ConsoleApplication1");
}
}
複製程式碼
這裡的getStringFromC
是靜態方法,getString2FromC
非靜態方法
標頭檔案:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class com_lwj_test_Test */
#ifndef _Included_com_lwj_test_Test
#define _Included_com_lwj_test_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_lwj_test_Test
* Method: getStringFromC
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_lwj_test_Test_getStringFromC
(JNIEnv *, jclass);
JNIEXPORT jstring JNICALL Java_com_lwj_test_Test_getString2FromC
(JNIEnv *, jclass,jint);
#ifdef __cplusplus
}
#endif
#endif
複製程式碼
標頭檔案Java_com_lwj_test_Test_getStringFromC
方法中jclass
是指:Test.class
;
標頭檔案Java_com_lwj_test_Test_getString2FromC
方法中jclass
是指Test
類例項化的t
物件。
訪問屬性方法
修改Java類的屬性 Java類:
public class Test {
public native static String getStringFromC();
public native String getString2FromC(int i);
public String name = "xiaoming";
//訪問屬性,返回修改之後的屬性內容
public native String updateName();
public static void main(String[] args) {
// TODO Auto-generated method stub
Test t = new Test();
System.out.print("修改前:"+t.name+"\n");
t.updateName();
System.out.print("修改後:"+t.name);
}
//載入動態庫
static {
System.loadLibrary("ConsoleApplication1");
}
}
複製程式碼
通過native方法的updateName
修改屬性name
C實現:
JNIEXPORT jstring JNICALL Java_com_lwj_test_Test_updateName
(JNIEnv *env, jobject jobj){
//得到class
jclass jcls = (*env)->GetObjectClass(env, jobj);
//獲取jfieldID 需要屬性名稱,屬性簽名
jfieldID fid = (*env)->GetFieldID(env, jcls, "name", "Ljava/lang/String;");
//獲取值
jstring jstr = (*env)->GetObjectField(env, jobj, fid);
//jstring->char
//iscopy:Null,這裡只需要傳NULL即可,需不需要copy一份,不是我們能控制的,是函式內部控制
char *str1 = (*env)->GetStringUTFChars(env,jstr,NULL);
//char *str1 = (*env)->GetStringUTFChars(env, jstr, JNI_FALSE);
char str2[30] = "my name is ";
//strcat(str2, str1);
strcat_s(str2,30,str1);
//c字串 ->jstring
jstring new_jstr = (*env)->NewStringUTF(env, str2);
//修改name的值,Set<Type>Field
(*env)->SetObjectField(env, jobj, fid, new_jstr);
return new_jstr;
}
複製程式碼
生成動態庫之後複製到Java工程下,執行得到
屬性簽名
上面jfieldID fid = (*env)->GetFieldID(env, jcls, "name", "Ljava/lang/String;");
需要傳入String的屬性簽名。
關於屬性簽名可以檢視下面的表格:
方法簽名
1)開啟cmd 2)進入Java專案的bin目錄 3)使用javap命令: javap 如: javap -s -p com.lwj.test.Test
訪問靜態屬性
Java類
public class Test {
public native static String getStringFromC();
public native String getString2FromC(int i);
public String name = "xiaoming";
//訪問屬性,返回修改之後的屬性內容
public native String updateName();
public static int count = 90;
//訪問靜態屬性的本地
public native void accessStaticField();
public static void main(String[] args) {
// TODO Auto-generated method stub
Test t = new Test();
System.out.print("修改前:"+count+"\n");
t.accessStaticField();
System.out.print("修改後:"+count);
}
//載入動態庫
static {
System.loadLibrary("ConsoleApplication1");
}
}
複製程式碼
標頭檔案新增方法
JNIEXPORT jstring JNICALL Java_com_lwj_test_Test_accessStaticField
(JNIEnv *, jobject);
複製程式碼
C實現方法
JNIEXPORT jstring JNICALL Java_com_lwj_test_Test_accessStaticField
(JNIEnv *env, jobject jobj){
//jclass
jclass jcls = (*env)->GetObjectClass(env, jobj);
//jfieldID
jfieldID fid = (*env)->GetStaticFieldID(env, jcls, "count", "I");
//GetStatic<Type>Field
jint count = (*env)->GetStaticIntField(env,jcls,fid);
count++;
//SetStatic<Type>Field
(*env)->SetStaticIntField(env, jcls, fid, count);
}
複製程式碼
生成動態庫,執行得到結果:
訪問java方法
JAVA 類
public class Test {
public native static String getStringFromC();
public native String getString2FromC(int i);
public String name = "123";
//訪問屬性,返回修改之後的屬性內容
public native String updateName();
public static int count = 90;
//訪問靜態屬性的本地
public native void accessStaticField();
public native void accessMethod();
public static void main(String[] args) {
// TODO Auto-generated method stub
Test t = new Test();
t.accessMethod();
}
/**
* 提供給native呼叫
* @return
*/
public int count(int a,int b) {
return a+b;
}
//載入動態庫
static {
System.loadLibrary("ConsoleApplication1");
}
}
複製程式碼
標頭檔案新增方法
JNIEXPORT jstring JNICALL Java_com_lwj_test_Test_accessMethod
(JNIEnv *, jobject);
複製程式碼
實現方法
//訪問java方法
JNIEXPORT jstring JNICALL Java_com_lwj_test_Test_accessMethod
(JNIEnv *env, jobject jobj){
//jclass
jclass cls = (*env)->GetObjectClass(env,jobj);
//jmethodID
jmethodID mid = (*env)->GetMethodID(env,cls,"count","(II)I");
//呼叫
//Call<Type>Method
jint count = (*env)->CallIntMethod(env, jobj, mid, 100, 200);
printf("count:%ld", count);
}
複製程式碼
這裡需要拿到方法的簽名,利用上面的方法簽名的方法即可拿到簽名。
訪問Java靜態方法
Java類
public class Test {
public native static String getStringFromC();
public native String getString2FromC(int i);
public String name = "123";
//訪問屬性,返回修改之後的屬性內容
public native String updateName();
public static int count = 90;
//訪問靜態屬性的本地
public native void accessStaticField();
public native void accessMethod();
public native void accessStaticMethod();
public static void main(String[] args) {
// TODO Auto-generated method stub
Test t = new Test();
t.accessStaticMethod();
}
/**
* 提供給native呼叫
* @return
*/
public int count(int a,int b) {
return a+b;
}
/**
* 產生UUID字串
* @return
*/
public static String getUUID(){
return UUID.randomUUID().toString();
}
//載入動態庫
static {
System.loadLibrary("ConsoleApplication1");
}
}
複製程式碼
標頭檔案新增方法
JNIEXPORT jstring JNICALL Java_com_lwj_test_Test_accessStaticMethod
(JNIEnv *, jobject);
複製程式碼
實現方法
JNIEXPORT jstring JNICALL Java_com_lwj_test_Test_accessStaticMethod
(JNIEnv *env, jobject jobj){
//jclass
jclass cls = (*env)->GetObjectClass(env, jobj);
//jmethodID
jmethodID mid = (*env)->GetStaticMethodID(env, cls, "getUUID", "()Ljava/lang/String;");
//呼叫
//CallStatic<Type>Method
jstring uuid = (*env)->CallStaticObjectMethod(env, cls, mid);
//隨機檔名稱 uuid.txt
//jstring -> char*
//isCopy JNI_FALSE,代表java和c操作的是同一個字串
char *uuid_str = (*env)->GetStringUTFChars(env, uuid, JNI_FALSE);
//拼接
char filename[100];
sprintf(filename, "D://%s.txt", uuid_str);
FILE *fp = fopen(filename, "w");
fputs("陰天快樂", fp);
fclose(fp);
printf("finish");
}
複製程式碼
執行結果:
開啟檔案
以上就是JNI訪問Java的資料型別和屬性方法