(创建于2017/11/18)
提示:
生成一个类中所有属性成员签名的方法如下:
1.进入这个类class文件所在的路径:如JniUtils这个类在d盘下 D:\application\java\eclipse-workspace\TestJni\bin\com\renzhenming\bsdiff>
2.执行命令D:\application\java\eclipse-workspace\TestJni\bin\com\renzhenming\bsdiff>javap -p -s JniUtils
3.会得到结果:descriptor所对应的就是签名
Compiled from "JniUtils.java"
public class com.renzhenming.bsdiff.JniUtils {
public static int key;
descriptor: I
static {};
descriptor: ()V
public com.renzhenming.bsdiff.JniUtils();
descriptor: ()V
public native void changeIntKey();
descriptor: ()V
public native void accessMethod();
descriptor: ()V
public native void accessStaticMethod();
descriptor: ()V
public int getRandomInt(int);
descriptor: (I)I
public static java.lang.String getUUId();
descriptor: ()Ljava/lang/String;
}
生成系统类签名的方法,以java.util.Date为例
直接进入命令行,输入javap -s -p 完整类名
C:\Users\renzhenming>javap -s -p java.util.Date
Compiled from "Date.java"
public class java.util.Date implements java.io.Serializable, java.lang.Cloneable, java.lang.Comparable {
private static final sun.util.calendar.BaseCalendar gcal;
descriptor: Lsun/util/calendar/BaseCalendar;
private static sun.util.calendar.BaseCalendar jcal;
descriptor: Lsun/util/calendar/BaseCalendar;
private transient long fastTime;
descriptor: J
private transient sun.util.calendar.BaseCalendar$Date cdate;
descriptor: Lsun/util/calendar/BaseCalendar$Date;
private static int defaultCenturyStart;
descriptor: I
private static final long serialVersionUID;
descriptor: J
private static final java.lang.String[] wtb;
descriptor: [Ljava/lang/String;
private static final int[] ttb;
descriptor: [I
public java.util.Date();
descriptor: ()V
public java.util.Date(long);
descriptor: (J)V
public java.util.Date(int, int, int);
descriptor: (III)V
public java.util.Date(int, int, int, int, int);
descriptor: (IIIII)V
public java.util.Date(int, int, int, int, int, int);
descriptor: (IIIIII)V
public java.util.Date(java.lang.String);
descriptor: (Ljava/lang/String;)V
public java.lang.Object clone();
descriptor: ()Ljava/lang/Object;
public static long UTC(int, int, int, int, int, int);
descriptor: (IIIIII)J
public static long parse(java.lang.String);
descriptor: (Ljava/lang/String;)J
public int getYear();
descriptor: ()I
public void setYear(int);
descriptor: (I)V
public int getMonth();
descriptor: ()I
public void setMonth(int);
descriptor: (I)V
public int getDate();
descriptor: ()I
public void setDate(int);
descriptor: (I)V
public int getDay();
descriptor: ()I
public int getHours();
descriptor: ()I
public void setHours(int);
descriptor: (I)V
public int getMinutes();
descriptor: ()I
public void setMinutes(int);
descriptor: (I)V
public int getSeconds();
descriptor: ()I
public void setSeconds(int);
descriptor: (I)V
public long getTime();
descriptor: ()J
private final long getTimeImpl();
descriptor: ()J
public void setTime(long);
descriptor: (J)V
public boolean before(java.util.Date);
descriptor: (Ljava/util/Date;)Z
public boolean after(java.util.Date);
descriptor: (Ljava/util/Date;)Z
public boolean equals(java.lang.Object);
descriptor: (Ljava/lang/Object;)Z
static final long getMillisOf(java.util.Date);
descriptor: (Ljava/util/Date;)J
public int compareTo(java.util.Date);
descriptor: (Ljava/util/Date;)I
public int hashCode();
descriptor: ()I
public java.lang.String toString();
descriptor: ()Ljava/lang/String;
private static final java.lang.StringBuilder convertToAbbr(java.lang.StringBuilder, java.lang.String);
descriptor: (Ljava/lang/StringBuilder;Ljava/lang/String;)Ljava/lang/StringBuilder;
public java.lang.String toLocaleString();
descriptor: ()Ljava/lang/String;
public java.lang.String toGMTString();
descriptor: ()Ljava/lang/String;
public int getTimezoneOffset();
descriptor: ()I
private final sun.util.calendar.BaseCalendar$Date getCalendarDate();
descriptor: ()Lsun/util/calendar/BaseCalendar$Date;
private final sun.util.calendar.BaseCalendar$Date normalize();
descriptor: ()Lsun/util/calendar/BaseCalendar$Date;
private final sun.util.calendar.BaseCalendar$Date normalize(sun.util.calendar.BaseCalendar$Date);
descriptor: (Lsun/util/calendar/BaseCalendar$Date;)Lsun/util/calendar/BaseCalendar$Date;
private static final sun.util.calendar.BaseCalendar getCalendarSystem(int);
descriptor: (I)Lsun/util/calendar/BaseCalendar;
private static final sun.util.calendar.BaseCalendar getCalendarSystem(long);
descriptor: (J)Lsun/util/calendar/BaseCalendar;
private static final sun.util.calendar.BaseCalendar getCalendarSystem(sun.util.calendar.BaseCalendar$Date);
descriptor: (Lsun/util/calendar/BaseCalendar$Date;)Lsun/util/calendar/BaseCalendar;
private static final synchronized sun.util.calendar.BaseCalendar getJulianCalendar();
descriptor: ()Lsun/util/calendar/BaseCalendar;
private void writeObject(java.io.ObjectOutputStream) throws java.io.IOException;
descriptor: (Ljava/io/ObjectOutputStream;)V
private void readObject(java.io.ObjectInputStream) throws java.io.IOException, java.lang.ClassNotFoundException;
descriptor: (Ljava/io/ObjectInputStream;)V
public static java.util.Date from(java.time.Instant);
descriptor: (Ljava/time/Instant;)Ljava/util/Date;
public java.time.Instant toInstant();
descriptor: ()Ljava/time/Instant;
public int compareTo(java.lang.Object);
descriptor: (Ljava/lang/Object;)I
static {};
descriptor: ()V
}
C:\Users\renzhenming>
1.在Java的一个类中,如下,定义各种类型的属性和方法
import java.util.Random;
import java.util.UUID;
public class JniUtils {
public String key = "renzhenming";
private 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 void accessNonVirtualMethod();
public native String toChineseString(String value);
public native void accessConstructor();
public native void setArray(int [] arr);
public native int[] getArray();
public native void cached();
public native static void initIds();
public static void main(String[] args) {
String text = getStringFromC();
System.out.println(text);
JniUtils t = new JniUtils();
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();
System.out.println("访问构造方法");
new JniUtils().accessConstructor();
System.out.println("访问被子类重写后的父类方法");
new JniUtils().accessNonVirtualMethod();
System.out.println(new JniUtils().toChineseString("想乱码的日子里"));
int arr [] = {12,3,43,55,44,1,566};
new JniUtils().setArray(arr);
for(int i = 0 ; i < arr.length;i++ ) {
System.out.println(arr[i]);
}
System.out.println("-------------------------------");
int [] jarr = new JniUtils().getArray();
for(int i = 0 ; i < jarr.length;i++ ) {
System.out.println(jarr[i]);
}
System.out.println("-------------------------------");
new JniUtils().createGlobalRef();
System.out.println(new JniUtils().getGlobalRef());
new JniUtils().deleteGlobalRef();
//释放了再获取就会空指针
//System.out.println(new JniUtils().getGlobalRef());
try {
new JniUtils().exception();
} catch (Exception e) {
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("JniTest");//这是生成的dll动态库的名字
initIds();
}
}
//类Human和类Man代码如下(测试jni调用父类方法而设置):
public class Human {
public void sayHi() {
System.out.println("人打招呼");
}
}
public class Man extends Human{
public void sayHi() {
System.out.println("男。。。。。人打招呼");
}
}
2.创建native方法,使用javah生成头文件,eclipse是进入到项目的src目录 javah com.xxx.xxx,如果提示错误: 编码GBK的不可映射字符,加上encoding javah -encoding URF-8 com.xxx.xxx
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class com_dongnaoedu_jni_JniTest */
#ifndef _Included_com_renzhenming_bsdiff_JniUtils
#define _Included_com_renzhenming_bsdiff_JniUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: _com_renzhenming_bsdiff_JniUtils
* Method: getStringFromC
* Signature: ()V
*/
JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getStringFromC
(JNIEnv *, jclass);
JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getString2FromC
(JNIEnv *, jobject, jint);
JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessField
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessStaticField
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessMethod
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessStaticMethod
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessConstructor
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessNonVirtualMethod
(JNIEnv *, jobject);
JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_toChineseString
(JNIEnv *, jobject, jstring);
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_setArray
(JNIEnv *,jobject,jintArray);
JNIEXPORT jintArray JNICALL Java_com_renzhenming_bsdiff_JniUtils_getArray
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_localRef
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_createGlobalRef
(JNIEnv *,jobject);
JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getGlobalRef
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_deleteGlobalRef
(JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_exception
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
3.将头文件引入as中(jni.h和jni_md.h引入同上次笔记),编写c代码,如下
#define _CRT_SECURE_NO_WARNINGS
#include "com_renzhenming_bsdiff_JniUtils.h"
#include
//功能:获取到指定类中一字符串类型成员变量,修改返回得到新的字符串
JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_changeKey
(JNIEnv *env, jobject jobj) {
//我们编写的native方法是非静态方法,所以这里是jobject,而我们需要jclass来获取fieldid,所以这样转换
jclass clazz = (*env)->GetObjectClass(env, jobj);
//参数分别为class对象,属性名,属性签名(签名得到的方法查看文档),获取到我们需要修改的属性的id值
jfieldID fieldId = (*env)->GetFieldID(env, clazz, "key", "Ljava/lang/String;");
//从这个对象jobj中获取这个id fieldid的jstring 对象
jstring jstr = (*env)->GetObjectField(env, jobj, fieldId);
//将jni类型jstring 转换为c对象char ,从而我们可以调用c方法修改这个对象的值
char *c_str = (*env)->GetStringUTFChars(env, jstr, JNI_FALSE);
//将这个对象的值和text这个字符串连接得到我们需要的新值
char text[30] = "handsome ";
strcat(text, c_str);
//再次将这个新值对应的c对象char转换为jni类型jstring,
jstring new_jstr = (*env)->NewStringUTF(env, text);
//将这个jstring类型的新对象设置给这个jobj这个对象中id值为fieldId的这个对象,至此对象值已经被我们修改
(*env)->SetObjectField(env, jobj, fieldId, new_jstr);
//删除
(*env)->DeleteLocalRef(env,new_jstr);
//返回这个新的字符串,这里没有用到
return new_jstr;
}
#define _CRT_SECURE_NO_WARNINGS
#include "com_renzhenming_bsdiff_JniUtils.h"
#include
//函数实现
JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getStringFromC
(JNIEnv *env, jclass jcls){
return (*env)->NewStringUTF(env,"C String");
}
JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getString2FromC
(JNIEnv *env, jobject jobj, jint num){
return (*env)->NewStringUTF(env,"C String2");
}
//每个native函数,都至少有两个参数(JNIEnv*,jclass或者jobject)
//1)当native方法为静态方法时:
//jclass 代表native方法所属类的class对象(JniTest.class)
//2)当native方法为非静态方法时:
//jobject 代表native方法所属的对象
//基本数据
//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
//C/C++访问Java的成员
//1.访问属性
//修改属性key
JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessField
(JNIEnv *env, jobject jobj){
//我们编写的native方法是非静态方法,所以这里是jobject,而我们需要jclass来获取fieldid,所以这样转换
jclass clazz = (*env)->GetObjectClass(env, jobj);
//参数分别为class对象,属性名,属性签名(签名得到的方法查看文档),获取到我们需要修改的属性的id值
jfieldID fieldId = (*env)->GetFieldID(env, clazz, "key", "Ljava/lang/String;");
//从这个对象jobj中获取这个id fieldid的jstring 对象
jstring jstr = (*env)->GetObjectField(env, jobj, fieldId);
//将jni类型jstring 转换为c对象char ,从而我们可以调用c方法修改这个对象的值
char *c_str = (*env)->GetStringUTFChars(env, jstr, JNI_FALSE);
//将这个对象的值和text这个字符串连接得到我们需要的新值
char text[30] = "handsome ";
strcat(text, c_str);
//再次将这个新值对应的c对象char转换为jni类型jstring,
jstring new_jstr = (*env)->NewStringUTF(env, text);
//将这个jstring类型的新对象设置给这个jobj这个对象中id值为fieldId的这个对象,至此对象值已经被我们修改
(*env)->SetObjectField(env, jobj, fieldId, new_jstr);
(*env)->DeleteLocalRef(env,new_jstr);
//返回这个新的字符串,这里没有用到
return new_jstr;
}
//访问静态属性
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessStaticField
(JNIEnv *env, jobject jobj){
//jclass
jclass cls = (*env)->GetObjectClass(env, jobj);
//jfieldID
jfieldID fid = (*env)->GetStaticFieldID(env, cls, "count", "I");
//GetStaticField
jint count = (*env)->GetStaticIntField(env, cls, fid);
count++;
//修改
//SetStaticField
(*env)->SetStaticIntField(env,cls,fid,count);
}
//2.访问java方法
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessMethod
(JNIEnv *env, jobject jobj){
//jclass
jclass cls = (*env)->GetObjectClass(env, jobj);
//jmethodID
jmethodID mid = (*env)->GetMethodID(env, cls, "genRandomInt", "(I)I");
//调用
//CallMethod
jint random = (*env)->CallIntMethod(env, jobj, mid, 200);
printf("random num:%ld",random);
//.....
}
//静态方法
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessStaticMethod
(JNIEnv *env, jobject jobj){
//jclass
jclass cls = (*env)->GetObjectClass(env, jobj);
//jmethodID
jmethodID mid = (*env)->GetStaticMethodID(env, cls, "getUUID", "()Ljava/lang/String;");
//调用
//CallStaticMethod
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);
//w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
FILE *fp = fopen(filename,"w");
fputs("i love jason", fp);
fclose(fp);
}
//访问构造方法(Date 生成一个时间戳)
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessConstructor
(JNIEnv *env, jobject jobj) {
//根据包名得到类,类似反射
jclass cls = (*env)->FindClass(env, "java/util/Date");
//获取类中要获取的方法id(获取构造方法,方法名传"")
jmethodID methodid = (*env)->GetMethodID(env, cls, "", "()V");
//实例化一个对象,类似反射
jobject date_obj = (*env)->NewObject(env, cls, methodid);
//通过这个对象调用getTime方法,需要获取到这个方法的id
jmethodID g_methodid = (*env)->GetMethodID(env, cls, "getTime", "()J");
//执行这个方法,返回值是long类型,所以CallLong
jlong time = (*env)->CallLongMethod(env, date_obj, g_methodid);
//占位符用的lld,是long long类型的,如果直接用ld占位符打印,打出的是负数
printf("\ntime:%lld\n", time);
(*env)->DeleteLocalRef(env,date_obj);
}
//访问父类被子类重写的方法
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessNonVirtualMethod
(JNIEnv *env, jobject jobj) {
//在java中,父类指向子类对象,调用被子类重写的方法,执行的是子类的方法,在jni中
//我们可以调用到父类的方法
jclass cls = (*env)->GetObjectClass(env, jobj);
//获取类中human属性(先获取到id) 对象的签名
jfieldID fid = (*env)->GetFieldID(env, cls, "human", "Lcom/renzhenming/bsdiff/Human;");
jobject human_obj = (*env)->GetObjectField(env, jobj, fid);
//获取父类class
jclass human_class = (*env)->FindClass(env, "com/renzhenming/bsdiff/Human");
//获取父类中需要调用的方法的methodid
jmethodID s_mid = (*env)->GetMethodID(env,human_class,"sayHi","()V");
//执行指定方法
//子类方法
(*env)->CallObjectMethod(env, human_obj, s_mid);
//父类方法(c++中要重写父类方法,用的是virtual关键字)(调用父类方法传入的class不能通过
//GetObjectClass从human_obj中获取,因为这样获取到的是子类的class)
(*env)->CallNonvirtualObjectMethod(env, human_obj, human_class, s_mid);
}
//解决jni中文乱码的问题
//java 内部是使用的 16 bit 的 unicode 编码(utf-16)来表示字符串的,无论英文还是中文都是 2 字节。
//JNI 内部是使用 utf-8 编码来表示字符串的,utf-8 是变长编码的 unicode,一般 ascii 字符是 1 字节,中文是 3 字节。
//C/C++ 使用的是原始数据,ascii 就是一个字节,中文一般是 GB2312 编码,用 2 个字节表示一个汉字。
//GetStringUTFChars,这个函数将得到一个 UTF-8 编码的字符串;
//另一个是 GetStringChars 这个将得到 UTF-16 编码的字符串。无论那个函数,得到的字符串如果含有中文,
//都需要进一步转化成 GB2312 的编码。
//两种解决方式,第一,就是下边这种,Java传递字符串到c中,c中通过java中的String构造方法,将接收到的字符串转成GB2312的编码格式
//第二,是直接在Java中将字符串转成GB2312编码的byte数组,然后传递到c中
//byte[] byteArry = strToJNI.getBytes("GB2312");
JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_toChineseString_
(JNIEnv *env, jobject jobj, jstring jstr) {
//输出
//char *c_str = (*env)->GetStringUTFChars(env, in, JNI_FALSE);
//printf("%s\n",c_str);
//c -> jstring
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, "", "([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);
}
//-----------------------操作数组涉及到数组的同步问题(ReleaseIntArrayElements)-----------------------------//
//操作传入的数组
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_setArray
(JNIEnv *env, jobject jobj, jintArray array) {
//jintArray ->jint指针->c int数组
jint *elems = (*env)->GetIntArrayElements(env, array, JNI_FALSE);
//数组的长度
int len = (*env)->GetArrayLength(env, array);
//排序(传入的compare类似Java中的比较器)
qsort(elems, len, sizeof(jint), compare);
//将排序结果同步到Java中的数组
//最后一个参数 mode
//0 表示Java数组进行更新,并且释放c/c++数组
//JNI_ABORT 表示Java数组不更新,释放c/c++数组
//JNI_COMMIT 表示Java数组进行更新,但不释放c/c++数组
(*env)->ReleaseIntArrayElements(env, array, elems, 0);
}
//返回一个数组
JNIEXPORT jintArray JNICALL Java_com_renzhenming_bsdiff_JniUtils_getArray
(JNIEnv *env, jobject jobj) {
//创建一个指定大小的数组
jintArray jint_arr = (*env)->NewIntArray(env, 10);
//获取到数组指针
jint *elems = (*env)->GetIntArrayElements(env, jint_arr, NULL);
int i = 0;
for ( ; i< 10; i++)
{
elems[i] = i;
}
//同步
(*env)->ReleaseIntArrayElements(env, jint_arr, elems, 0);
return jint_arr;
}
//局部引用
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_localRef
(JNIEnv *env, jobject jobj) {
int i = 0;
for (; i < 5; i++) {
//创建对象,以Date为例
jclass cls = (*env)->FindClass(env, "java/util/Date");
jmethodID constructor_id = (*env)->GetMethodID(env, cls, "init", "()V");
jobject obj = (*env)->NewObject(env, cls, constructor_id);
//....
//不在使用这个对象了需要回收
(*env)->DeleteLocalRef(env, obj);
//....
}
}
//创建全局引用(共享,可以跨多个线程)
jstring global_str;
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_createGlobalRef
(JNIEnv *env, jobject jobj) {
jstring jstr = (*env)->NewStringUTF(env,"jni is a bitch");
global_str = (*env)->NewGlobalRef(env, jstr);
}
//获取全局引用
JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getGlobalRef
(JNIEnv *env, jobject jobj) {
return global_str;
}
//删除全局引用
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_deleteGlobalRef
(JNIEnv *env, jobject jobj) {
(*env)->DeleteGlobalRef(env, global_str);
}
//Java捕获c异常(如果不做抛异常处理,直接再Java层try是抓不到异常信息的)
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_exception
(JNIEnv *env, jobject jobj) {
jclass cls = (*env)->GetObjectClass(env, jobj);
jfieldID fid = (*env)->GetFieldID(env, cls, "value2", "Ljava/lang/String;");
//检测是否发生Java异常
jthrowable exception = (*env)->ExceptionOccurred(env);
if (exception != NULL) {
//让Java代码可以继续运行
//清空异常信息
(*env)->ExceptionClear(env);
//补救措施
fid = (*env)->GetFieldID(env, cls, "value", "Ljava/lang/String;");
}
//获取属性值
jstring jstr = (*env)->GetObjectField(env, jobj, fid);
char *str = (*env)->GetStringUTFChars(env, jstr, NULL);
//对比属性是否合法
if (stricmp(str, "renzhenming") != 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_renzhenming_bsdiff_JniUtils_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");
}
}
//加载动态库的时候就初始化全局变量,再loadLibrary后调用
jfieldID key_fid;
jmethodID random_mid;
JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_initIds(JNIEnv *env, jclass jcls){
key_fid = (*env)->GetFieldID(env, jcls, "key", "Ljava/lang/String;");
random_mid = (*env)->GetMethodID(env, jcls, "genRandomInt", "(I)I");
}
4.生成dll动态库,放到eclipse中调用
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();
System.out.println("访问构造方法");
new JniUtils().accessConstructor();
System.out.println("访问被子类重写后的父类方法");
new JniUtils().accessNonVirtualMethod();
System.out.println(new JniUtils().toChineseString("想乱码的日子里"));
int arr [] = {12,3,43,55,44,1,566};
new JniUtils().setArray(arr);
for(int i = 0 ; i < arr.length;i++ ) {
System.out.println(arr[i]);
}
System.out.println("-------------------------------");
int [] jarr = new JniUtils().getArray();
for(int i = 0 ; i < jarr.length;i++ ) {
System.out.println(jarr[i]);
}
System.out.println("-------------------------------");
new JniUtils().createGlobalRef();
System.out.println(new JniUtils().getGlobalRef());
new JniUtils().deleteGlobalRef();
//释放了再获取就会空指针
//System.out.println(new JniUtils().getGlobalRef());
try {
new JniUtils().exception();
} catch (Exception e) {
System.out.println("发生异常:"+e.getMessage());
}
}