上一节中我们学习了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的数据类型和属性方法