JNI

#1. c里面 JNIEnv是个二级指针,c++里直接是个指针,因为c++里有this指针表示结构体自己;
#2. JNIEnv代表java运行环境,在c中调用java代码
#3. java调用的native方法命名规则 Java_完整类名_方法名(JNIEnv * env,jobject thiz......)
#4. jni里的对象都是通过gc进行管理的;
每个native方法至少有两个参数JNIEnv ,jclass(静态)或者jobject(非静态)
静态方法:jclass代表native方法所在java类的class对象;
非静态方法:jobject代表native方法所属的对象;

#数据类型
java类型 ——>JNI类型——> c类型
String jstring
object jobject
byte[] jByteArray
object[](String[])jobjectArray
boolean jboolean(JNI_TRUE,JNI_FALSE)

写好java 的native方法之后,cmd到src目录下,用“ javah 完整类名” 生成头文件.h

#define _CRT_SECURE_NO_WARNINGS//必须放在最上面
#include <stdio.h>
#include <string.h>
#include "com_jack_TestJni.h"

#define log(args,...) printf(args,__VA_ARGS__);

JNIEXPORT void JNICALL Java_com_jack_TestJni_change
(JNIEnv *env, jobject jobj){
	jclass cls = (*env)->GetObjectClass(env, jobj);
	//获取签名的方法:cmd, cd 到java工程所在的bin目录,javap -s -private 完整类名
	jfieldID valueId = (*env)->GetFieldID(env, cls, "value", "I");

	jint value = (*env)->GetIntField(env, jobj, valueId);

	//基础的数据类型 jni的类型和c类型不用相互转化
	printf("original value is : %d\n", value);

	(*env)->SetIntField(env, jobj, valueId, 27);
	//注意不要忘记最后的分号
	jfieldID textId = (*env)->GetFieldID(env, cls, "text", "Ljava/lang/String;");
	//获取对象类型
	jstring jtext = (*env)->GetObjectField(env, jobj, textId);

	//最后的isCopy参数如果为JNI_TRUE 的话,会报错
//isCopy 为指针类型,在函数执行过程中赋值,
//isCopy=JNI_TRUE 为复制; isCopy=JNI_FALSE 为不复制,c和java指向同一字符串,不能修改
	//要在c函数中使用java字符串,必须转换String-> jstring -> char*
	char *cOriginalText = (*env)->GetStringUTFChars(env, jtext, JNI_FALSE);
	printf("original text is : %s\n", cOriginalText);

	


	jmethodID methId = (*env)->GetMethodID(env, cls, "getText", "()Ljava/lang/String;");
	jstring jstr = (*env)->CallObjectMethod(env, jobj, methId);
	char *cOriginaljstr = (*env)->GetStringUTFChars(env, jstr, JNI_FALSE);
	printf("original jstr from method : %s\n", cOriginaljstr);

	//设置新的对象值
	char* cText = "gloria";
	jstring newText = (*env)->NewStringUTF(env, cText);
	(*env)->SetObjectField(env, jobj, textId, newText);
(*env)->ReleaseStringUTFChars(env, newText , cText);//释放字符串


	//----------------------以下是操作java静态成员---------------------------
	//获取静态属性id
	jfieldID staticStrId = (*env)->GetStaticFieldID(env, cls, "staticText", "Ljava/lang/String;");
	//获取静态属性
	jstring staticStr = (*env)->GetStaticObjectField(env, cls, staticStrId);
	char *cStr = (*env)->GetStringUTFChars(env, staticStr, JNI_FALSE);
	printf("static text from java is : %s \n", cStr);


	cStr=strcat(cStr, " is change 哈哈哈哈----------");


	//-------------通过调用java的string构造方法解决中文乱码问题-----------
	jclass strCls = (*env)->FindClass(env, "java/lang/String");
	//获取构造方法
	jmethodID cId = (*env)->GetMethodID(env, strCls, "<init>", "([BLjava/lang/String;)V");

	int lenth = strlen(cStr);
	jbyteArray bytes = (*env)->NewByteArray(env,lenth );
	(*env)->SetByteArrayRegion(env, bytes, 0, lenth, cStr);
	jstring char_set = (*env)->NewStringUTF(env, "gb2312");

	jstring result = (*env)->NewObject(env, strCls, cId, bytes, char_set);
	
	//设置静态属性的值
	(*env)->SetStaticObjectField(env, cls, staticStrId, result);


	//---------------调用静态方法------------------

	/*jmethodID method= (*env)->GetStaticMethodID(env, cls, "setStaticText", "(Ljava/lang/String;)V");
	char* c = "hello from c";
	jstring njs = (*env)->NewStringUTF(env, c);
	(*env)->CallStaticVoidMethod(env, cls, method, njs);*/

	//---------------------创建java对象---------------------
	jclass date = (*env)->FindClass(env, "java/util/Date");
	//获取构造方法
	jmethodID constructorId = (*env)->GetMethodID(env, date, "<init>", "()V");
	jobject dateInstance = (*env)->NewObject(env, date, constructorId);
	jmethodID methodId = (*env)->GetMethodID(env, date, "getTime", "()J");
	jlong time = (*env)->CallLongMethod(env, dateInstance, methodId);
	printf("current time is : %lld \n", time);

	//----------------------访问父类的方法----------------------------
	jclass childCls = (*env)->GetObjectClass(env, jobj);
	jclass superCls = (*env)->FindClass(env, "com/jack/SuperClass");
	jmethodID m = (*env)->GetMethodID(env, superCls, "sayHello", "()V");
	(*env)->CallObjectMethod(env, jobj, m);
	(*env)->CallNonvirtualObjectMethod(env, jobj, superCls, m);
}

//------------操作数组------------------
//必须用指针,否则不能交换位置
int compare(int* a, int* b){
	return (*a) - (*b);
}


JNIEXPORT void JNICALL Java_com_jack_TestJni_sort
(JNIEnv *env, jobject obj,jintArray array){

	int size = (*env)->GetArrayLength(env, array);
	jint* arrayP = (*env)->GetIntArrayElements(env, array, NULL);
	qsort(arrayP, size, sizeof(jint), compare);
	//最后一个参数
	//0,Java数组更新,并且释放c数组
	//JNI_COMMIT ,java数组更新,不释放c数组,可继续使用
	//JNI_ABORT(2) java数组不更新,释放c数组
	(*env)->ReleaseIntArrayElements(env, array, arrayP, JNI_ABORT);


	//-------------jni 的异常捕获-------------
	//JNI自己抛出的异常,可以在java层被捕捉
	//用户通过(*env)->ThrowNew(env);抛出的异常,在java层可以捕获;
	jclass cls = (*env)->GetObjectClass(env, obj);
	//获取静态属性id
//没有这个字段,java.lang.NoSuchFieldError可以用throwable捕获到
	jfieldID staticStrId = (*env)->GetStaticFieldID(env, cls, "staticText22222", "Ljava/lang/String;");
	/*int arr[] = { 1, 2, 3, 4, 5, 0 };
	for (int var = 0; var < 6;var++)
	{
		int i = 100 / arr[var];
	}*/
	//检查是否出现java,jni异常,不能捕获c的异常(c 本来就没有异常捕获的措施),比如上面的除数为0的异常
	jthrowable exc = (*env)->ExceptionOccurred(env);
	if (exc != NULL){//清空异常,保证java代码继续执行
		printf("--------jni catch java exception------------");
		(*env)->ExceptionClear(env);
		//抛出异常
		jclass newExcCls = (*env)->FindClass(env, "java/lang/Exception");
		(*env)->ThrowNew(env, newExcCls, "error");//这样抛出的异常可以被捕获
	}
}



void (JNICALL *DeleteGlobalRef) (JNIEnv *env, jobject gref);//用于jni中 删除全局引用
void (JNICALL *DeleteLocalRef) (JNIEnv *env, jobject obj);//删除局部引用
弱全局引用WeakGlobalRef

static 声明在函数内的局部静态变量
static int ;//作用域只在函数内,生命周期直到程序退出结束。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值