java代码
public class JniTestModle {
public String keys = "keyy";
public native int accessMethod();
public native int accessStaticMethod();
public native String accessStaticMethodString();
public native Date accessConstractor();
public native String chineessChars(String str);
public native String chineessCharsString(String str);
public native void giveArray(int[] arr);
public native String[] initStringArray(int size);
public native void localref();
public native void createGolbalRef();
public native String getGolbalRef();
public native void delGolbalRef();
public native void exception();
public native void cached();
public native static void cachedGlobal();
static {
System.loadLibrary("JNI_C2_C7");
}
public static void main(String[] args) {
JniTestModle jt = new JniTestModle();
jt.accessMethod();
System.out.println(jt.accessMethod());
System.out.println(jt.accessStaticMethod());
System.out.println(jt.accessStaticMethodString());
System.out.println(jt.accessConstractor() + "......");
System.out.println(jt.chineessChars("宝宝"));
System.out.println(jt.chineessCharsString("宝宝"));
int[] arr = { 12, 45, 65, 87, 1, 2, 54 };
jt.giveArray(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
String[] str = jt.initStringArray(2);
for (int i = 0; i < str.length; i++) {
System.out.print(str[i]);
}
jt.localref();
jt.createGolbalRef();
System.out.println(jt.getGolbalRef());
jt.delGolbalRef();
try {
jt.exception();
} catch (Exception e) {
// TODO: handle exception
// IllegalArgumentException
System.out.println(e.toString());
}
System.out.println("................");
jt.cached();
jt.cachedGlobal();
}
int getRandomInt(int max) {
return new Random().nextInt(max);
}
static int accessStaticInt(int max) {
return new Random().nextInt(max);
}
static String accessStaticString() {
String str = UUID.randomUUID().toString();
return str;
}
}
C代码
#include "stdafx.h"
#include "jnitest_JniTestModle.h"
#include <Windows.h>
#include <string.h>
JNIEXPORT jint JNICALL Java_jnitest_JniTestModle_accessMethod
(JNIEnv * env, jobject jobj){
int a = 0;
//jclass
jclass jclz = (*env)->GetObjectClass(env, jobj);
//jmethId 方法名字,方法签名
jmethodID mid = (*env)->GetMethodID(env, jclz, "getRandomInt", "(I)I");
//调用
a = (*env)->CallIntMethod(env, jobj, mid, 2000);
return a;
};
//访问静态方法 int 基本数据类型
JNIEXPORT jint JNICALL Java_jnitest_JniTestModle_accessStaticMethod
(JNIEnv *env, jobject jobj){
int a = 0;
//jclass
jclass jclz = (*env)->GetObjectClass(env, jobj);
//jmethId 方法名字,方法签名
jmethodID mid = (*env)->GetStaticMethodID(env, jclz, "accessStaticInt", "(I)I");
//调用
a = (*env)->CallStaticIntMethod(env, jobj, mid, 2000);
return a;
};
//访问静态方法 引用类型方法
JNIEXPORT jstring JNICALL Java_jnitest_JniTestModle_accessStaticMethodString
(JNIEnv *env, jobject jobj){
//jclass
//给了类的对象找class
jclass jclz = (*env)->GetObjectClass(env, jobj);
//jmethId 方法名字,方法签名
jmethodID mid = (*env)->GetStaticMethodID(env, jclz, "accessStaticString", "()Ljava/lang/String;");
//调用
jstring jstr = (*env)->CallStaticObjectMethod(env, jobj, mid);
printf("%s\n", jstr);
char * c_str = (*env)->GetStringUTFChars(env, jstr, NULL);
printf("%s\n", c_str);
char fileName[100];
sprintf(fileName, "D://%s.text", c_str);
FILE *fp = fopen(fileName, "w");
fputs("I Love Me", fp);
fclose(fp);
printf("文件写入成功!\n");
return jstr;
};
//访问构造方法 所有java中
JNIEXPORT jobject JNICALL Java_jnitest_JniTestModle_accessConstractor
(JNIEnv *env, jobject jobj)
{//jclass 给了类的名字让后根据名字找类
jclass jclz = (*env)->FindClass(env, "java/util/Date");
//所有构造方法都是传<init>
jmethodID jmid = (*env)->GetMethodID(env, jclz, "<init>", "()V");
//实例化 调用NewObject实例化Date对象,返回值是一个jobject
//所有引用类型都转换成 jobject
//第三个参数 后面的构造器中传参一次传
jobject date_obj = (*env)->NewObject(env, jclz, jmid);
//jmethodID long 型 是J
jmethodID time_id = (*env)->GetMethodID(env, jclz, "getTime", "()J");
//返回值
jlong time = (*env)->CallLongMethod(env, date_obj, time_id);
printf("time : %lld\n", time);
return date_obj;
};
//可以不定义,防止第三方调用,直接创建使用
//编码方式 java ;utf-16 16bit 2字节 JNI utf-8英文1字节 中文3字节
//c/c++ ASCII编码 中文的编码方式GB2312 编码,中文2个字节
//字符乱码1 (两种解决方式)
JNIEXPORT jstring JNICALL Java_jnitest_JniTestModle_chineessChars
(JNIEnv *env, jobject jobj, jstring str){
jboolean iscrp;
//传指针之后,获得参数结果
char *c_str = (*env)->GetStringUTFChars(env, str, &iscrp);
if (iscrp == JNI_TRUE){
printf("is copy :JNI_TRUE \n");
}
else if (iscrp == JNI_FALSE){
printf("is copy :JNI_FALSE \n");
}
int length = (*env)->GetStringLength(env, str, NULL);
//jchar ->char
const jchar * jcstr = (*env)->GetStringChars(env, str, NULL);
if (jcstr == NULL){
return NULL;
}
char *rtn = (char *)malloc(sizeof(char)*length * 2 + 3);
memset(rtn, 0, sizeof(char)* 2 * length + 3);
int size = 0;
size = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)jcstr,
length, rtn, sizeof(char)*length * 2 + 3, NULL, NULL);
/*if (size <= 0){
printf("%d\n", size);
return NULL;
}*/
printf("rtn : %s\n", rtn);
if (rtn != NULL){
free(rtn);
rtn = NULL;
}
if (iscrp == JNI_TRUE){
//Jvm使用 ,通知JVM 可以释放 c_str 所指的空间可以释放了
(*env)->ReleaseStringChars(env, str, c_str);
}
return str;
};
//字符乱码2
JNIEXPORT jstring JNICALL Java_jnitest_JniTestModle_chineessCharsString
(JNIEnv *env, jobject jobj, jstring str){
char *c_str = "你说就是了abb";
jclass str_cls = (*env)->FindClass(env, "java/lang/String");
jmethodID jmid = (*env)->GetMethodID(env, str_cls, "<init>", "([BLjava/lang/String;)V");
//jstring ->jbyteArray
jbyteArray bytes = (*env)->NewByteArray(env, strlen(c_str));
//将char *赋值到bytes
(*env)->SetByteArrayRegion(env, bytes, 0, strlen(c_str), c_str);
jstring charseName = (*env)->NewStringUTF(env, "GB2312");
//直接使用构造器
jstring strq = (*env)->NewObject(env, str_cls, jmid, bytes, charseName);
return strq;
};
//访问数组 基本数据类型数组引用类型的数组
JNIEXPORT void JNICALL Java_jnitest_JniTestModle_giveArray
(JNIEnv *env, jobject jobj, jarray arr){
int compare(jint *a, jint *b);
//转换数组
jint *elemts = (*env)->GetIntArrayElements(env, arr, NULL);
//系统提供的快速排序
if (elemts == NULL){
return NULL;
}
int len = (*env)->GetArrayLength(env, arr);
qsort(elemts, len, sizeof(jint), compare);
//释放可能的内存
//将JNI 修改的数据重新写回原来的内存
(*env)->ReleaseIntArrayElements(env, arr, elemts, JNI_COMMIT);
};
int compare(jint *a, jint *b){
return *a - *b;
}
//访问引用类型的数据
JNIEXPORT jobjectArray JNICALL Java_jnitest_JniTestModle_initStringArray
(JNIEnv *env, jobject jobj, jint size){
//创建
jobjectArray result;
jclass jclz;
jclz = (*env)->FindClass(env, "java/lang/String");
if (jclz == NULL){
return NULL;
}
result = (*env)->NewObjectArray(env, size, jclz, jobj);
if (result == NULL){
return NULL;
}
//赋值
int i;
for (i = 0; i < size; i++)
{
//c字符串
char *c_str = (char*)malloc(256);
memset(c_str, 0, 256);
//将int 转化成为char
sprintf(c_str, "hello num : %d\n", i);
//c->jstring
jstring str = (*env)->NewStringUTF(env, c_str);
if (str == NULL){
return NULL;
}
//将就string 赋值给数组
(*env)->SetObjectArrayElement(env, result, i, str);
free(c_str);
c_str = NULL;
}
//返回
return result;
};
//JNI 引用
//局部引用
//全局引用
//弱全局引用
//局部引用 定义方式多样:Findclass NewObject ,GetObjectClass,NewCharArray....
//NewLocalRef()
//释放方式:方法调用完,JVM会自动释放
// 手动释放(局部引用表最多502个引用)
//局部引用不能再多线程中使用,只能在定义的地方使用
//全局引用
//跨线程,夸方法使用
//局部引用
JNIEXPORT void JNICALL Java_jnitest_JniTestModle_localref
(JNIEnv *env, jobject jobj){
int i = 0;
for (i = 0; i < 5; i++)
{
jclass cls = (*env)->FindClass(env, "java/util/Date");
jmethodID mid = (*env)->GetMethodID(env, cls, "<init>", "()V");
//创建一个 Date 类型的局部引用
jobject obj = (*env)->NewObject(env, cls, mid);
//使用这个引用
jmethodID time_id = (*env)->GetMethodID(env, cls, "getTime", "()J");
//返回值
jlong time = (*env)->CallLongMethod(env, obj, time_id);
printf("localref : %lld\n", time);
// 释放引用 局部引用表最多502个引用 不然那引用表溢出
(*env)->DeleteLocalRef(env, obj);
(*env)->DeleteLocalRef(env, cls);
}
};
//全局引用 跨线程,跨方法
jstring global_str;
JNIEXPORT void JNICALL Java_jnitest_JniTestModle_createGolbalRef
(JNIEnv *env, jobject jobj){
jobject obj = (*env)->NewStringUTF(env, "JNI is intersting");
//创建全局引用的唯一方法NewGlobalRef
global_str = (*env)->NewGlobalRef(env, obj);
printf("%s\n", global_str);
};
JNIEXPORT jstring JNICALL Java_jnitest_JniTestModle_getGolbalRef
(JNIEnv *env, jobject jobj){
return global_str;
};
JNIEXPORT void JNICALL Java_jnitest_JniTestModle_delGolbalRef
(JNIEnv *env, jobject jobj){
(*env)->DeleteGlobalRef(env, global_str);
};
//若全局引用
//他不会阻止GC 跨进程,跨方法
jclass g_weak_clz;
JNIEXPORT void JNICALL Java_jnitest_JniTestModle_createlweakRef
(JNIEnv *env, jobject jobj){
jclass jclz = (*env)->FindClass(env, "java/lang/String");
g_weak_clz = (*env)->NewWeakGlobalRef(env, jclz);
};
//C语言中异常了 java就不能正常走下去了
//JNI 异常处理
//异常可以写一个工具类
JNIEXPORT void JNICALL Java_jnitest_JniTestModle_exception
(JNIEnv *env, jobject jobj){
jclass jclz = (*env)->GetObjectClass(env, jobj);
jfieldID fid = (*env)->GetFieldID(env, jclz, "key", "Ljava/lang/String;");
//检测是否发生异常
jthrowable ex = (*env)->ExceptionOccurred(env);
//判断异常是否发送
if (ex != NULL)
{
jclass newExc;
//清空JNI 产生的异常
(*env)->ExceptionClear(env);
//ILLegalArgumentException
newExc = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
if (newExc == NULL)
{
return NULL;
}
(*env)->ThrowNew(env, newExc, "Throw exception from JNI: GetFieldID faild");
}
printf("exception\n");
};
//缓存策略
JNIEXPORT void JNICALL Java_jnitest_JniTestModle_cached
(JNIEnv *env, jobject jobj){
jclass cls = (*env)->GetObjectClass(env, jobj);
//静态局部变量 生命周期很长 存放在静态内存区
//减少使用 Gc出现就出现野指针
static jfieldID fid = NULL;
if (fid == NULL)
{
fid = (*env)->GetFieldID(env, cls, "keys", "Ljava/lang/String;");
printf("GetFieldID int \n");
}
printf("GetFieldID out \n");
};
//全局的静态变量 不要static 全局都能是使用
static jfieldID fid; //所有正在他定义行数之后 才起效果,在它定义的前面的方法访问不到
JNIEXPORT void JNICALL Java_jnitest_JniTestModle_cachedGlobal
(JNIEnv *env, jobject obj){
jclass jclz = (*env)->GetObjectClass(env, obj);
if (fid == NULL)
{
fid = (*env)->GetFieldID(env, jclz, "keys", "Ljava/lang/String;");
jstring str = (*env)->GetObjectField(env, obj, fid);
printf("str : %s \n", str);
printf("GetFieldIDStatic int \n");
}
printf("GetFieldIDStatic out \n");
};