Jni使用
来源:互联网 发布:js 拼接字符串 编辑:程序博客网 时间:2024/04/28 20:58
今天暂时写到这里,有时间继续总结全面
概述jni(Java Native Interface)是什么?
它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。jni主要解决java限制的事情,或者要进行高效开发。
最简单的jni使用
package com.dongnaoedu.jni;public class JniTest { public native static String getStringFromC(); public static void main(String[] args) { String text = getStringFromC(); System.out.println(text); } //加载动态库 static{ System.loadLibrary("jni_demo"); }}
头文件:
#include <jni.h>#ifndef _Included_com_dongnaoedu_jni_JniTest#define _Included_com_dongnaoedu_jni_JniTest#ifdef __cplusplusextern "C" {#endif/* * Class: com_dongnaoedu_jni_JniTest * Method: getStringFromC * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_dongnaoedu_jni_JniTest_getStringFromC (JNIEnv *, jclass);#ifdef __cplusplus}#endif#endif
实现:
#include "com_dongnaoedu_jni_JniTest.h"JNIEXPORT jstring JNICALL Java_com_dongnaoedu_jni_JniTest_getStringFromC(JNIEnv *env, jclass jcls){ //JNIEnv 在C++中就是一个结构体的别名 //env 在C++中一个结构体的一级指针 return env->NewStringUTF("C String");}
注意的细节
具体介绍:
每个native函数,都至少有两个参数(JNIEnv*,jclass或者jobject)
- 1)当native方法为静态方法时:
jclass 代表native方法所属类的Class对象(JniTest.class)
- 2)当native方法为非静态方法时:
jobject 和一个数组和java.lang.Object类或它的子类的实例对应
基本数据
- Java基本数据类型与JNI数据类型的映射关系
- Java类型->JNI类型->C类型
基本数据类型
基本类型 boolean jboolean byte jbyte; char jchar; short jshort; int jint; long jlong; float jfloat; double jdouble; void void引用类型(对象) String jstring object jobject数组,基本数据类型的数组 byte[] jByteArray对象数组 object[](String[]) jobjectArray
java代码:
package com.dongnaoedu.jni;import java.util.Date;import java.util.Random;import java.util.UUID;import javax.sql.rowset.CachedRowSet;public class JniTest { public String key = "jason"; public Human human = new Man(); public static int count = 9; public native static String getStringFromC(); public native String getString2FromC(int i); //访问属性,返回修改之后的属性内容 public native String accessField(); public native void accessStaticField(); public native void accessMethod(); public native void accessStaticMethod(); public native Date accessConstructor(); public native void accessNonvirtualMethod(); public native String chineseChars(String in); public native void giveArray(int[] array); public native int[] getArray(int len); public native void localRef(); public native void createGlobalRef(); public native String getGlobalRef(); public native void deleteGlobalRef(); public native void exeception(); public native void cached(); public native static void initIds(); public static void main(String[] args) { String text = getStringFromC(); System.out.println(text); JniTest t = new JniTest(); text = t.getString2FromC(6); System.out.println(text); System.out.println("key修改前:"+t.key); t.accessField(); System.out.println("key修改后:"+t.key); System.out.println("count修改前:"+count); t.accessStaticField(); System.out.println("count修改后:"+count); t.accessMethod(); t.accessStaticMethod(); t.accessConstructor(); t.accessNonvirtualMethod(); System.out.println(t.chineseChars("宋喆")); int[] array = {9,100,10,37,5,10}; //排序 t.giveArray(array); for (int i : array) { System.out.println(i); } //---------- int[] array2 = t.getArray(10); System.out.println("------------"); for (int i : array2) { System.out.println(i); } System.out.println("------08-17------"); t.createGlobalRef(); System.out.println(t.getGlobalRef()); //用完之后释放 t.deleteGlobalRef(); System.out.println("释放完了..."); //System.out.println(t.getGlobalRef()); try { t.exeception(); } catch (Exception e) { System.out.println("发生异常:"+e.getMessage()); } System.out.println("--------异常发生之后-------"); try { t.exeception(); } catch (Exception e) { //e.printStackTrace(); System.out.println(e.getMessage()); } //不断调用cached方法 for (int i = 0; i < 100; i++) { t.cached(); } } //产生指定范围的随机数 public int genRandomInt(int max){ System.out.println("genRandomInt 执行了..."); return new Random().nextInt(max); } //产生UUID字符串 public static String getUUID(){ return UUID.randomUUID().toString(); } //加载动态库 static{ System.loadLibrary("jni_study"); initIds(); }}
#define _CRT_SECURE_NO_WARNINGS#include "com_dongnaoedu_jni_JniTest.h"#include <string.h>//返回字符串JNIEXPORT jstring JNICALL Java_com_dongnaoedu_jni_JniTest_getStringFromC(JNIEnv *env, jclass jcls){ return (*env)->NewStringUTF(env,"C String");}JNIEXPORT jstring JNICALL Java_com_dongnaoedu_jni_JniTest_getString2FromC(JNIEnv *env, jobject jobj, jint num){ return (*env)->NewStringUTF(env,"C String2");}//C/C++访问Java的成员//修改属性keyJNIEXPORT jstring JNICALL Java_com_dongnaoedu_jni_JniTest_accessField(JNIEnv *env, jobject jobj){ jclass cls = (*env)->GetObjectClass(env, jobj);//得到JniTest.class对象 jfieldID fid = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");//得到字段jfieldID jstring jstr = (*env)->GetObjectField(env, jobj, fid);//获取jfieldID对应字段的属性值 char *c_str = (*env)->GetStringUTFChars(env,jstr,JNI_FALSE);//将字符串转化 //拼接得到新的字符串 char text[20] = "super "; strcat(text,c_str); jstring new_jstr = (*env)->NewStringUTF(env, text); //c字符串 ->jstring (*env)->SetObjectField(env, jobj, fid, new_jstr);//设置字段的值 return new_jstr;}//访问静态属性JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_accessStaticField(JNIEnv *env, jobject jobj){ jclass cls = (*env)->GetObjectClass(env, jobj);//得到JniTest.class对象 jfieldID fid = (*env)->GetStaticFieldID(env, cls, "count", "I");//jfieldID jint count = (*env)->GetStaticIntField(env, cls, fid); //GetStatic<Type>Field count++; (*env)->SetStaticIntField(env,cls,fid,count);//SetStatic<Type>Field}//2.访问java方法JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_accessMethod(JNIEnv *env, jobject jobj){ jclass cls = (*env)->GetObjectClass(env, jobj); jmethodID mid = (*env)->GetMethodID(env, cls, "genRandomInt", "(I)I");//jmethodID jint random = (*env)->CallIntMethod(env, jobj, mid, 200);//Call<Type>Method}//静态方法JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_accessStaticMethod(JNIEnv *env, jobject jobj){ jclass cls = (*env)->GetObjectClass(env, jobj);//jclass jmethodID mid = (*env)->GetStaticMethodID(env, cls, "getUUID", "()Ljava/lang/String;");//jmethodID jstring uuid = (*env)->CallStaticObjectMethod(env, cls, mid);//CallStatic<Type>Method //isCopy JNI_FALSE,代表java和c操作的是同一个字符串 char *uuid_str = (*env)->GetStringUTFChars(env, uuid, JNI_FALSE);}-----------------------------------------------------------------//访问构造方法//使用java.util.Date产生一个当前的时间戳JNIEXPORT jobject JNICALL Java_com_dongnaoedu_jni_JniTest_accessConstructor(JNIEnv *env, jobject jobj){ jclass cls = (*env)->FindClass(env, "java/util/Date"); //jmethodID jmethodID constructor_mid = (*env)->GetMethodID(env, cls, "<init>", "()V"); //实例化一个Date对象 jobject date_obj = (*env)->NewObject(env, cls, constructor_mid); //调用getTime方法 jmethodID mid = (*env)->GetMethodID(env, cls, "getTime", "()J"); jlong time = (*env)->CallLongMethod(env, date_obj, mid); printf("\ntime:%lld\n",time); return date_obj;}//调用父类的方法JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_accessNonvirtualMethod(JNIEnv *env, jobject jobj){ jclass cls = (*env)->GetObjectClass(env, jobj); //获取man属性(对象) jfieldID fid = (*env)->GetFieldID(env, cls, "human", "Lcom/dongnaoedu/jni/Human;"); //获取 jobject human_obj = (*env)->GetObjectField(env, jobj, fid); //执行sayHi方法 jclass human_cls = (*env)->FindClass(env, "com/dongnaoedu/jni/Human"); //注意:传父类的名称 jmethodID mid = (*env)->GetMethodID(env, human_cls, "sayHi", "()V"); //执行 //(*env)->CallObjectMethod(env, human_obj, mid); //调用的父类的方法 (*env)->CallNonvirtualObjectMethod(env, human_obj, human_cls, mid);}//中文问题JNIEXPORT jstring JNICALL Java_com_dongnaoedu_jni_JniTest_chineseChars(JNIEnv *env, jobject jobj, jstring in){ char *c_str = "马蓉与宋江"; //char c_str[] = "马蓉与宋喆"; //jstring jstr = (*env)->NewStringUTF(env, c_str); //执行String(byte bytes[], String charsetName)构造方法需要的条件 //1.jmethodID //2.byte数组 //3.字符编码jstring jclass str_cls = (*env)->FindClass(env, "java/lang/String"); jmethodID constructor_mid = (*env)->GetMethodID(env, str_cls, "<init>", "([BLjava/lang/String;)V"); //jbyte -> char //jbyteArray -> char[] jbyteArray bytes = (*env)->NewByteArray(env, strlen(c_str)); //byte数组赋值 //0->strlen(c_str),从头到尾 //对等于,从c_str这个字符数组,复制到bytes这个字符数组 (*env)->SetByteArrayRegion(env, bytes, 0, strlen(c_str), c_str); //字符编码jstring jstring charsetName = (*env)->NewStringUTF(env, "GB2312"); //调用构造函数,返回编码之后的jstring return (*env)->NewObject(env,str_cls,constructor_mid,bytes,charsetName);}int compare(int *a,int *b){ return (*a) - (*b);}//传入JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_giveArray(JNIEnv *env, jobject jobj, jintArray arr){ //jintArray -> jint指针 -> c int 数组 jint *elems = (*env)->GetIntArrayElements(env, arr, NULL); //数组的长度 int len = (*env)->GetArrayLength(env, arr); //排序 qsort(elems, len, sizeof(jint), compare); //同步 //mode //0, Java数组进行更新,并且释放C/C++数组 //JNI_ABORT, Java数组不进行更新,但是释放C/C++数组 //JNI_COMMIT,Java数组进行更新,不释放C/C++数组(函数执行完,数组还是会释放) (*env)->ReleaseIntArrayElements(env, arr, elems, JNI_COMMIT);}//返回数组JNIEXPORT jintArray JNICALL Java_com_dongnaoedu_jni_JniTest_getArray(JNIEnv *env, jobject jobj, jint len){ //创建一个指定大小的数组 jintArray jint_arr = (*env)->NewIntArray(env, len); jint *elems = (*env)->GetIntArrayElements(env, jint_arr, NULL); int i = 0; for (; i < len; i++){ elems[i] = i; } //同步 (*env)->ReleaseIntArrayElements(env, jint_arr, elems, 0); return jint_arr;}//JNI 引用变量//引用类型:局部引用和全局引用//作用:在JNI中告知虚拟机何时回收一个JNI变量//局部引用,通过DeleteLocalRef手动释放对象//1.访问一个很大的java对象,使用完之后,还要进行复杂的耗时操作//2.创建了大量的局部引用,占用了太多的内存,而且这些局部引用跟后面的操作没有关联性//模拟:循环创建数组JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_localRef(JNIEnv *env, jobject jobj){ int i = 0; for (; i < 5; i++){ //创建Date对象 jclass cls = (*env)->FindClass(env, "java/util/Date"); jmethodID constructor_mid = (*env)->GetMethodID(env, cls, "<init>", "()V"); jobject obj = (*env)->NewObject(env, cls, constructor_mid); //此处省略一百行代码... //不在使用jobject对象了 //通知垃圾回收器回收这些对象 (*env)->DeleteLocalRef(env, obj); //此处省略一百行代码... }}//全局引用//共享(可以跨多个线程),手动控制内存使用jstring global_str;//创建JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_createGlobalRef(JNIEnv *env, jobject jobj){ jstring obj = (*env)->NewStringUTF(env, "jni development is powerful!"); global_str = (*env)->NewGlobalRef(env, obj);}//获得JNIEXPORT jstring JNICALL Java_com_dongnaoedu_jni_JniTest_getGlobalRef(JNIEnv *env, jobject jobj){ return global_str;}//释放JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_deleteGlobalRef(JNIEnv *env, jobject jobj){ (*env)->DeleteGlobalRef(env, global_str);}//弱全局引用//节省内存,在内存不足时可以是释放所引用的对象//可以引用一个不常用的对象,如果为NULL,临时创建//创建:NewWeakGlobalRef,销毁:DeleteGlobalWeakRef//异常处理//1.保证Java代码可以运行//2.补救措施保证C代码继续运行//JNI自己抛出的异常,在Java层无法被捕捉,只能在C层清空//用户通过ThrowNew抛出的异常,可以在Java层捕捉JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_exeception(JNIEnv *env, jobject jobj){ jclass cls = (*env)->GetObjectClass(env, jobj); jfieldID fid = (*env)->GetFieldID(env, cls, "key2", "Ljava/lang/String;"); //检测是否发生Java异常 jthrowable exception = (*env)->ExceptionOccurred(env); if (exception != NULL){ //让Java代码可以继续运行 //清空异常信息 (*env)->ExceptionClear(env); //补救措施 fid = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;"); } //获取属性的值 jstring jstr = (*env)->GetObjectField(env, jobj, fid); char *str = (*env)->GetStringUTFChars(env, jstr, NULL); //对比属性值是否合法 if (_stricmp(str, "super jason") != 0){ //认为抛出异常,给Java层处理 jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); (*env)->ThrowNew(env,newExcCls,"key's value is invalid!"); }}//缓存策略//static jfieldID key_id JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_cached(JNIEnv *env, jobject jobj){ jclass cls = (*env)->GetObjectClass(env, jobj); //获取jfieldID只获取一次 //局部静态变量 static jfieldID key_id = NULL; if (key_id == NULL){ key_id = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;"); printf("--------GetFieldID-------\n"); }}//初始化全局变量,动态库加载完成之后,立刻缓存起来jfieldID key_fid;jmethodID random_mid;JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_initIds(JNIEnv *env, jclass jcls){ key_fid = (*env)->GetFieldID(env, jcls, "key", "Ljava/lang/String;"); random_mid = (*env)->GetMethodID(env, jcls, "genRandomInt", "(I)I");}
小结基础:
jclass对象是java中对象所对应的Class对象jobject对象是java中的对象实体得到jclass的方式:1.jclass cls = (*env)->GetObjectClass(env, jobj);2.jclass cls = (*env)->FindClass(env, "java/util/Date");得到jobject对象的方式:jclass cls = (*env)->FindClass(env, "java/util/Date");jmethodID constructor_mid = (*env)->GetMethodID(env, cls, "<init>", "()V");jobject date_obj = (*env)->NewObject(env, cls, constructor_mid);//实例化一个Date对象得到jfieldID方式:1.jfieldID fid = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");//非静态2.jfieldID fid = (*env)->GetStaticFieldID(env, cls, "count", "I");//静态得到jmethodID方式:1.jmethodID mid = (*env)->GetMethodID(env, cls, "genRandomInt", "(I)I");//jmethodID2.jmethodID mid = (*env)->GetStaticMethodID(env, cls, "getUUID", "()Ljava/lang/String;");//jmethodID 通过jfieldID找到对应的字段值方式:1.jstring jstr = (*env)->GetObjectField(env, jobj, fid);2.jint count = (*env)->GetStaticIntField(env, cls, fid); //GetStatic<Type>Field通过jmethodID找到对应方法的方式:1.jint random = (*env)->CallIntMethod(env, jobj, mid, 200);//Call<Type>Method2.jstring uuid = (*env)->CallStaticObjectMethod(env, cls, mid);//CallStatic<Type>Method派生类调用父类方法:jclass cls = (*env)->GetObjectClass(env, jobj);jfieldID fid = (*env)->GetFieldID(env, cls, "human", "Lcom/dongnaoedu/jni/Human;");jobject human_obj = (*env)->GetObjectField(env, jobj, fid);//得到Human派生类对象//执行sayHi方法jclass man_cls = (*env)->FindClass(env, "com/dongnaoedu/jni/Man"); //注意:传父类的名称jmethodID mid = (*env)->GetMethodID(env, man_cls, "sayHi", "()V");(*env)->CallNonvirtualObjectMethod(env, human_obj, man_cls, mid);//需要派生类jobject和父类的jclass和父类的jmethodID
0 0
- JNI使用
- JNI使用
- Jni 使用
- JNI 使用
- jni使用
- JNI使用
- Jni使用
- JNI使用
- JNI使用技巧点滴
- JNI使用技巧点滴
- JNI的使用(ZT)
- JNI 的使用
- 使用jni调用unrar
- JNI的使用
- JNI 简单使用小结
- jni得简单使用
- JNI使用技巧点滴
- 使用j2se的jni
- 四月的主要任务
- GreenDAO使用笔记
- android字体带下划线
- 工作辅助工具
- JavaEE开发之Spring中的多线程编程以及任务定时器详解
- Jni使用
- Promise example
- maven核心概念
- 蓝桥杯-基础练习 字母图形
- 基于Spring Boot和Spring Cloud实现微服务架构学习(一)-Spring框架介绍
- [DLX 数独 模板题] HDU 1426 Sudoku Killer
- 非官方win7 64位 python 图像库
- poj 2348
- 开发遇到的小问题归纳