Jni学习笔记(1)

jni.h文件必须包含, 定义了所有jni函数声明和数据类型

JNIEnv结构包含了JNI函数表
第二个参数取决于该方法是静态还是实例调用, 是实例的话第二个参数就是实例本身, 静态的话指向类

1.签名
用于解决方法重载问题



Java方法例子:
long f(int n, String s, int[] arr);
签名: "(ILjava/lang/String;[I)J"

注意:
类描述符开头必须有L, 结尾必须有;
数组描述符开头必须有[
方法描述符 (各个参数描述符)返回值描述符, 其中参数描述符之间没有任何分隔符号

2.访问成员变量
实例成员变量
Java_method(JNIEnv *env, jobject obj)
{
     jfieldID fid;
     jclass cls = (*env)->GetObjectClass(env, obj); //获得对象类
     fid = (*env)->GetFieldID(env, cls, "s", "Ljava/lang/String;"); //获得对象成员ID
     jstring jstr = (*env)->GetObjectField(env, obj, fid); //取得对象成员的值, 还有Get/SetIntField Get/SetFloatField
     const char *str = (*env)->GetStringUTFChars(env, jstr, NULL);
     ...
     (*env)->SetObjectField(env, obj, fid, jstr); //设置对象成员的值
}

静态成员变量
GetStaticFieldID
Get/SetStaticIntField之类的 //注意这里第二个参数传入的是cls


3.访问成员方法
实例成员方法
jmethodID mid = GetMethodID(env, cls, "methodName", "()V");
(*env)->CallVoidMethod(env, obj, mid); //命名规则, Call<Return Value Type>Method

静态成员方法
GetStaticMethodID
CallStatic<Return Value Type>Method //注意这里第二个参数传入的是cls

被子类覆盖的父类方法
一样GetMethodID
CallNonvirtualVoidMethod CallNonvirtualBooleanMethod //相当于super.f()

构造函数
构造函数的名称叫 "<init>"
result = (*env)->NewObject(env, cls, cid, param); //cid是构造函数jmethodID, param是传入构造函数的参数

也可以把创建对象和初始化分开
obj = (*env)->AllocObject(env, cls);
(*env)->CallNonvirtualVoidMethod(env, result, cls, cid, cls); //为啥这个是调用父类的方法??不是应该调用子类?


4.优化
用个hash表来缓存methodID, fieldID,用名字+签名做键值
安全的做法,连同类的初始化缓存Method/Field ID


5.引用
LocalRef 防止被GC回收
大概就是栈上的空间, 不能用static来缓存(如jclass就是LocalRef, 返回值为jobject/jclass等JNI函数)
native method返回(指的是返回到Java层, 从native函数返回native函数LocalRef是有效的, 跟栈上又不太一样), JVM自动释放LocalRef
用DeleteLocalRef主动释放(因为LocalRefTable是有限的防止溢出)

GlobalRef 防止被GC回收
必须是通过NewGlobalRef(env, cls)由程序员主动创建

Weak Global References 不保证不被GC
NewGlobalWeakRef
DeleteGlobalWeakRef

对当前上下文内使用的对象数量有准确的估计,建议使用PushLocalFrame(env, 10), PopLocalFrame(env, result)





你可能感兴趣的:(java,jvm,优化,String,jni,null)