JNI 常用API

JNI 常用API

 

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

■获取版本信息

■进行类和对象操作

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

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

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

■执行字串和数组操作

■产生和控制Java异常

 

获取版本信息

jint GetVersion(JNIEnv *env);

 

获取JNI函数版本信息,

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

In JDK/JRE 1.1, GetVersion() returns0x00010001.

In JDK/JRE 1.2, GetVersion() returns0x00010002.

In JDK/JRE 1.4, GetVersion() returns0x00010004.

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

 

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

 

参数:

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

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);

 

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

 

jthrowable ExceptionOccurred(JNIEnv *env);

 

测试JVM是否有异常发生

 

SINCE JDK/JRE 1.2:

 

 

local reference 和 global reference。

 

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

 

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

 

jobject NewGlobalRef(JNIEnv *env, jobject obj);

 

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

参数:

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

 

void DeleteGlobalRef(JNIEnv *env, jobjectglobalRef);

 

销毁全局引用

参数:

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

 

 void DeleteLocalRef(JNIEnv *env, jobjectlocalRef);

 

销毁本地的引用

 

注意:

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

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

jint EnsureLocalCapacity(JNIEnv *env, jintcapacity);

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

jint PushLocalFrame(JNIEnv *env, jintcapacity);

 

jobject PopLocalFrame(JNIEnv *env, jobjectresult);

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

jobject NewLocalRef(JNIEnv *env, jobjectref);

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 GlobalReferences

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

jweak NewWeakGlobalRef(JNIEnv *env, jobjectobj);

void DeleteWeakGlobalRef(JNIEnv *env, jweakobj);

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 theconstructor.

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

jclass GetObjectClass(JNIEnv *env, jobjectobj);

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

jboolean IsInstanceOf(JNIEnv *env, jobjectobj,
jclass clazz);

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

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

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

 

Accessing Fields of Objects

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

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

参数:

Name属性在java类中的名字

Sig 类型签名

Get<type>FieldRoutines

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

                                     

表 3-3   Get<type>FieldFamily of Accessor Routines

Get<type>FieldRoutine Name

Native Type

GetObjectField()

jobject

GetBooleanField()

jboolean

GetByteField()

jbyte

GetCharField()

jchar

GetShortField()

jshort

GetIntField()

jint

GetLongField()

jlong

GetFloatField()

jfloat

GetDoubleField()

jdouble

获取java对象属性的值

Set<type>FieldRoutines

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

表 3-4   Set<type>FieldFamily of Accessor Routines

Set<type>FieldRoutine Name

Native Type

SetObjectField()

jobject

SetBooleanField()

jboolean

SetByteField()

jbyte

SetCharField()

jchar

SetShortField()

jshort

SetIntField()

jint

SetLongField()

jlong

SetFloatField()

jfloat

SetDoubleField()

jdouble

设置java对象属性的值

Calling Instance Methods

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

GetMethodID得到java类中方法的ID,它只能调用类中声明为public的方法,jmethodIDCall<type>Method函数族使用

参数:

Name方法在java类中的名字

Sig 类型签名

NativeTypeCall<type>Method(JNIEnv*env, jobject obj,
jmethodID methodID, ...);

NativeTypeCall<type>MethodA(JNIEnv*env, jobject obj,
jmethodID methodID, jvalue *args);

NativeTypeCall<type>MethodV(JNIEnv*env, jobject obj,
jmethodID methodID, va_list args);

表 3-5   Instance Method Calling Routines

Call<type>MethodRoutine Name

Native Type

CallVoidMethod()

CallVoidMethodA()

CallVoidMethodV()

void

 

CallObjectMethod()

CallObjectMethodA()

CallObjectMethodV()

jobject

 

CallBooleanMethod()

CallBooleanMethodA()

CallBooleanMethodV()

jboolean

 

CallByteMethod()

CallByteMethodA()

CallByteMethodV()

jbyte

 

CallCharMethod()

CallCharMethodA()

CallCharMethodV()

jchar

 

CallShortMethod()

CallShortMethodA()

CallShortMethodV()

jshort

 

CallIntMethod()

CallIntMethodA()

CallIntMethodV()

jint

 

CallLongMethod()

CallLongMethodA()

CallLongMethodV()

jlong

 

CallFloatMethod()

CallFloatMethodA()

CallFloatMethodV()

jfloat

 

CallDoubleMethod()

CallDoubleMethodA()

CallDoubleMethodV()

jdouble

 

 

调用java方法通过jmethodID指定

如果想要调用一个对象的父类方法,而不是子类的这个方法的话,就可以使用NativeTypeCallNonvirtual<type>Method(JNIEnv*env, jobject obj,
jclass clazz, jmethodID methodID, ...);

NativeTypeCallNonvirtual<type>MethodA(JNIEnv*env, jobject obj,
jclass clazz, jmethodID methodID, jvalue *args);

NativeTypeCallNonvirtual<type>MethodV(JNIEnv*env, jobject obj,
jclass clazz, jmethodID methodID, va_list args);

表 3-6 CallNonvirtual<type>MethodRoutines

CallNonvirtual<type>Method Routine Name

Native Type

CallNonvirtualVoidMethod()

CallNonvirtualVoidMethodA()

CallNonvirtualVoidMethodV()

void

 

CallNonvirtualObjectMethod()

CallNonvirtualObjectMethodA()

CallNonvirtualObjectMethodV()

jobject

 

CallNonvirtualBooleanMethod()

CallNonvirtualBooleanMethodA()

CallNonvirtualBooleanMethodV()

jboolean

 

CallNonvirtualByteMethod()

CallNonvirtualByteMethodA()

CallNonvirtualByteMethodV()

jbyte

 

CallNonvirtualCharMethod()

CallNonvirtualCharMethodA()

CallNonvirtualCharMethodV()

jchar

 

CallNonvirtualShortMethod()

CallNonvirtualShortMethodA()

CallNonvirtualShortMethodV()

jshort

 

CallNonvirtualIntMethod()

CallNonvirtualIntMethodA()

CallNonvirtualIntMethodV()

jint

 

CallNonvirtualLongMethod()

CallNonvirtualLongMethodA()

CallNonvirtualLongMethodV()

jlong

 

CallNonvirtualFloatMethod()

CallNonvirtualFloatMethodA()

CallNonvirtualFloatMethodV()

jfloat

 

CallNonvirtualDoubleMethod()

CallNonvirtualDoubleMethodA()

CallNonvirtualDoubleMethodV()

jdouble

 

例:

  1. package com.cn;
  2.  
  3. public class Father {
  4. public void function(){
  5. System.out.println("Father:function");
  6. }
  7. }

 

1.  package com.cn;

2.  public class Child extendsFather {

3.  public void function() {

4. System.out.println("Child:function");

5.  }

6.  }

 

  1. package com.cn;
  2. public class TestNativeCall {
  3. public native void testCall ();
  4. public Father p = new Child();
  5. public static void main(String[] args) {
  6.  
  7. System.loadLibrary("nativeCode");//Java类中加载DLL,然后调用声明的native方法
  8. TestNativeCall tst=new TestNativeCall ();
  9. tst.testCall ();
  10. }
  11. }

 

 

 

  1. void Java_Com_Cn_ testCall (JNIEnv *env, jobject obj){
  2.  
  3. jfieldID id_p = env->GetFieldID(clazz_TestNative,"p","Lcom/cn/Father;");
  4. jobject p =env->GetObjectField(obj,id_p);//取得属性
  5.  
  6. jclass clazz_Father = env->FindClass("com/cn/Father");//找到Father类
  7. jmethodID id_Father_function =env->GetMethodID(clazz_Father,"function","()V");//获取Father类里面方法的ID
  8.  
  9. //调用方法,取得的是子类方法
  10. env->CallVoidMethod(p,id_Father_function);
  11.  
  12. //调用父类方法
  13. env->CallNonvirtualVoidMethod(p,clazz_Father,id_Father_function);
  14. }

 

Accessing Static Fields

jfieldID GetStaticFieldID(JNIEnv *env, jclassclazz,
const char *name, const char *sig);

GetStaticFieldID得到java类中static属性ID,jfieldIDGetStatic<type>Fieldand SetStatic<type>Field函数族使用

参数:

clazz java类对象

name方法在java类中的名字

sig  类型签名

 

GetStatic<type>FieldRoutines

NativeTypeGetStatic<type>Field(JNIEnv*env, jclass clazz,
jfieldID fieldID);

表 3-7 

GetStatic<type>Field Family ofAccessor Routines

GetStatic<type>Field RoutineName

Native Type

GetStaticObjectField ()

jobject

GetStaticBooleanField ()

jboolean

GetStaticByteField ()

jbyte

GetStaticCharField ()

jchar

GetStaticShortField ()

jshort

GetStaticIntField ()

jint

GetStaticLongField ()

jlong

GetStaticFloatField ()

jfloat

GetStaticDoubleField ()

jdouble

 

获取java对象静态属性的值

 

SetStatic<type>FieldRoutines

voidSetStatic<type>Field(JNIEnv*env, jclass clazz,
jfieldID fieldID, NativeTypevalue);

 

表 3-8 

SetStatic<type>Field Family ofAccessor Routines

SetStatic<type>Field RoutineName

Native Type

SetStaticObjectField ()

jobject

SetStaticBooleanField ()

jboolean

SetStaticByteField ()

jbyte

SetStaticCharField ()

jchar

SetStaticShortField ()

jshort

SetStaticIntField ()

jint

SetStaticLongField ()

jlong

SetStaticFloatField ()

jfloat

SetStaticDoubleField ()

jdouble

设置java对象静态属性的值

 

 

Calling Static Methods

GetStaticMethodID

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

 

GetStaticMethodID得到java类中static方法ID,jmethodIDCallStatic<type>Method函数使用

 

NativeTypeCallStatic<type>Method(JNIEnv*env, jclass clazz,
jmethodID methodID, ...);

NativeTypeCallStatic<type>MethodA(JNIEnv*env, jclass clazz,
jmethodID methodID, jvalue *args);

NativeTypeCallStatic<type>MethodV(JNIEnv*env, jclass clazz,
jmethodID methodID, va_list args);

 

 

表 3-9 CallStatic<type>Method CallingRoutines

CallStatic<type>Method Routine Name

Native Type

CallStaticVoidMethod()

CallStaticVoidMethodA()

CallStaticVoidMethodV()

void

 

CallStaticObjectMethod()

CallStaticObjectMethodA()

CallStaticObjectMethodV()

jobject

 

CallStaticBooleanMethod()

CallStaticBooleanMethodA()

CallStaticBooleanMethodV()

jboolean

 

CallStaticByteMethod()

CallStaticByteMethodA()

CallStaticByteMethodV()

jbyte

 

CallStaticCharMethod()

CallStaticCharMethodA()

CallStaticCharMethodV()

jchar

 

CallStaticShortMethod()

CallStaticShortMethodA()

CallStaticShortMethodV()  

jshort

 

CallStaticIntMethod()

CallStaticIntMethodA()

CallStaticIntMethodV()

jint

 

CallStaticLongMethod()

CallStaticLongMethodA()

CallStaticLongMethodV()

jlong

 

CallStaticFloatMethod()

CallStaticFloatMethodA()

CallStaticFloatMethodV()

jfloat

 

CallStaticDoubleMethod()

CallStaticDoubleMethodA()

CallStaticDoubleMethodV()

jdouble

 

 

StringOperations

jstring NewString(JNIEnv *env, const jchar*unicodeChars,
jsize len);

Array Operations

Registering Native Methods

jint RegisterNatives(JNIEnv *env, jclassclazz,
const JNINativeMethod *methods, jint nMethods);

 

typedef struct {

 

    char *name;

 

    char*signature;

 

    void *fnPtr;

 

} JNINativeMethod

 

Monitor Operations

jint MonitorEnter(JNIEnv *env, jobject obj);

jint MonitorExit(JNIEnv *env, jobject obj);

 

NIO Support

The NIO-related entry points allow native code to accessjava.nio direct buffers. The contents of adirect buffer can, potentially, reside in native memory outside ofthe ordinary garbage-collected heap. For information about directbuffers, please see NewI/O APIs and the specification of the java.nio.ByteBuffer class.

Three new functions introduced in JDK/JRE 1.4 allow JNI code tocreate, examine, and manipulate direct buffers:

Reflection Support

 

Java VMInterface

jint GetJavaVM(JNIEnv *env, JavaVM**vm);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值