入门客AI创业平台(我带你入门,你带我飞行)
博文笔记

JNI 常用API

创建时间:2012-10-19 投稿人: 浏览次数:92

利用JNIEnv自变量,程序员可访问一系列函数。这些函数可划分为下述类别:

■获取版本信息

■进行类和对象操作

■控制对Java对象的全局和局部引用

■访问实例字段和静态字段

■调用实例方法和静态方法

■执行字串和数组操作

■产生和控制Java异常

 

获取版本信息

jint GetVersion(JNIEnv *env);

 

获取JNI函数版本信息,

返回值为jint类型,在c/c++中jint为32位数,其中高16位是主版本号,低16位是从版本号

In JDK/JRE 1.1, GetVersion() returns 0x00010001.

In JDK/JRE 1.2, GetVersion() returns 0x00010002.

In JDK/JRE 1.4, GetVersion() returns 0x00010004.

jclass FindClass(JNIEnv *env, const char *name);

 

CLASSPATH 环境变量中搜索目录和zip 文件中具有指定名称的类。

 

参数:

name: a fully-qualified class name  完全限定类 ,给出完整的类路径,包名和类名使用“/”隔开

SINCE JDK/JRE 1.2:

 

产生和控制Java异常

 

jint Throw(JNIEnv *env, jthrowable obj);

 

抛出异常

 

参数:jthrowable  是 java.lang.Throwable 包中对象.

 

jint ThrowNew(JNIEnv *env, jclass clazz,
const char *message);

 

通过消息构造一个异常类,其中参数clazz 为 java.lang.Throwable包中的子类

 

jthrowable ExceptionOccurred(JNIEnv *env);

 

测试JVM是否有异常发生

 

SINCE JDK/JRE 1.2:

 

 

local reference 和 global reference。

 

Java 和JNI代码之间函数调用时,简单类型,也就是内置类型,比如 int, char 等是值传递(pass by value),而其它 Java 对象都是引用传递(pass by reference),这些对象引用由 JVM 传给JNI代码,每个都有其生命周期。

 

JNI 函数参数中 jobject 或者它的子类,其参数都是 local reference。Local reference 只在这个 JNI函数中有效,JNI函数返回后,引用的对象就被释放,它的生命周期就结束了。若要留着日后使用,则需根据这个 local reference 创建 global reference。Global reference 不会被系统自动释放,它仅当被程序明确调用 DeleteGlobalReference 时才被回收。(JNI多线程机制)

 

jobject NewGlobalRef(JNIEnv *env, jobject obj);

 

创建一个新的全局的引用,只能使用DeleteGlobalRef()函数销毁这个全局引用

参数:

Obj 一个本地引用或者全局引用

 

void DeleteGlobalRef(JNIEnv *env, jobject globalRef);

 

销毁全局引用

参数:

globalRef 使用NewGlobalRef()函数生成的全局引用

 

 void DeleteLocalRef(JNIEnv *env, jobject localRef);

 

销毁本地的引用

 

注意:

JDK/JRE 1.1 提供了上面的 DeleteLocalRef 函数,使程序员可以手动删除本地引用。例如,如果本机代码遍历可能很大的对象或数组,并使用每个迭代中的一个元素,好的做法是下一次迭代中创建一个新的本地引用之前删除本地元素的引用。

JDK/JRE 1.2 和更高版本为本地引用生存周期管理提供了一套额外的函数。他们是下面列出的四种函数。

jint EnsureLocalCapacity(JNIEnv *env, jint capacity);

通知JVM 您将使用超过 16 个本地引用。这将允许 JVM 优化对该本机代码的本地引用的处理

jint PushLocalFrame(JNIEnv *env, jint capacity);

 

jobject PopLocalFrame(JNIEnv *env, jobject result);

先调用PushLocalFrame,然后创建局部引用,并对其进行处理,最后调用PushLocalFrame释放局部引用,这时Java虚拟机也可以对其指 向的对象进行垃圾回收。可以用C语言的栈来理解这对JNI API,调用PushLocalFrame之后Native代码创建的所有局部引用全部入栈,当调用PopLocalFrame之后,入栈的局部引用除了 需要返回的局部引用(PushLocalFrame和PopLocalFrame这对函数可以返回一个局部引用给外部)之外,全部出栈,Java虚拟机这 时可以释放他们指向的对象。具体的用法可以参考手册。这两个函数使JNI的局部引用由于和C语言的局部变量用法类似,所以强烈推荐使用

jobject NewLocalRef(JNIEnv *env, jobject ref);

1、Java虚拟机默认为Native引用分配的局部引用数量是有限的,大部分的Java虚拟机实现默认分配16个局部引用。当然Java虚拟 机也提供API(PushLocalFrame,EnsureLocalCapacity)让你申请更多的局部引用数量(Java虚拟机不保证你一定能申 请到)。有限的资源当然要省着点用,否则将会被Java虚拟机无情抛弃(程序崩溃)。JNI编程中,实现Native代码时强烈建议调用PushLocalFrame,EnsureLocalCapacity来确保Java虚拟机为你准备好了局部变量空间。

2、如果你实现的Native函数是工具函数,会被频繁的调用。如果你在Native函数中没有显示删除局部引用,那么每次调用该函数Java虚拟机都会创建一个新的局部引用,造成局部引用过多。尤其是该函数在Native代码中被频繁调用,代码的控制权没有交还给Java虚拟机,所以Java虚拟机根本没有机会释放这些局部变量。退一步讲,就算该函数直接返回给Java虚拟机,也不能保证没有问题,我们不能假设Native函数返回Java虚 拟机之后,Java虚拟机马上就会回收Native函数中创建的局部引用,依赖于Java虚拟机实现。所以我们在实现Native函数时一定要记着删除不 必要的局部引用,否则你的程序就有潜在的风险,不知道什么时候就会爆发。

3、如果你Native函数根本就不返回。比如消息循环函数——死循环等待消息,处理消息。如果你不显示删除局部引用,很快将会造成Java虚拟机的局部引用内存溢出。

Weak Global References

全局的弱引用是一种特殊的全局引用,与普通的全局引用不同全局的弱引用允许Java 对象进行垃圾回收,当垃圾收集器运行时,它将释放对象,如果引用的对象只使用弱引用

jweak NewWeakGlobalRef(JNIEnv *env, jobject obj);

void DeleteWeakGlobalRef(JNIEnv *env, jweak obj);

SINCE JDK/JRE 1.2:

Object Operations

jobject AllocObject(JNIEnv *env, jclass clazz);

分配一个新的 Java 对象,而不调用任何对象的构造函数,仅仅是内存创建

jobject NewObject(JNIEnv *env, jclass clazz,
jmethodID methodID, ...);

jobject NewObjectA(JNIEnv *env, jclass clazz,
jmethodID methodID, jvalue *args);

args: an array of arguments to the constructor.

jobject NewObjectV(JNIEnv *env, jclass clazz,
jmethodID methodID, va_list args);

args: a va_list of arguments to the constructor.

分配一个新的java对象,调用指定的构造函数,构造函数使用methodID指定

jclass GetObjectClass(JNIEnv *env, jobject obj);

根据类的引用返回类的类型

jboolean IsInstanceOf(JNIEnv *env, jobject obj,
jclass clazz);

测试类的引用类型,是返回JNI_TRUE 否则 返回JNI_FALSE

jboolean IsSameObject(JNIEnv *env, jobject ref1,
jobject ref2);

测试两个引用类型是否指向同一个空间,是返回JNI_TRUE 否则 返回JNI_FALSE

 

Accessing Fields of Objects

jfieldID GetFieldID(JNIEnv *env, jclass clazz,
const char *name, const char *sig);

GetFieldID是得到java类中的参数ID,只能调用类中声明为 public的属性,jfieldID Get<type>Field andSet<type>Field 函数族使用

参数:

Name 属性在java类中的名字

Sig 类型签名

Get<type>Field Routines

NativeType Get<type>Field(JNIEnv *env, jobject obj,
jfieldID fieldID);

                                      

表 3-3    Get<type>Field Family of Accessor Routines

Get<type>Field Routine Name

Native Type

GetObjectField()

jobject

GetBooleanField()

jboolean

GetByteField()

jbyte

GetCharField()

声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。