博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android JNI 学习(四):接口方法表 & Base Api & Exception Api
阅读量:5891 次
发布时间:2019-06-19

本文共 12149 字,大约阅读时间需要 40 分钟。

本文我们来总结一下JNI 提供的功能列表及相关的函数表。

注意:请注意使用术语“必须”来描述对JNI程序员的限制。例如,当您看到某个JNI函数必须接收非NULL对象时,您有责任确保不将NULL传递给该JNI函数。因此,JNI实现不需要在该JNI函数中执行NULL指针检查。

一、接口方法表

可以通过JNIEnv参数以固定偏移量访问每个函数。JNIEnv类型是一个指向存储所有JNI函数指针的结构。它的定义如下:

typedef const struct JNINativeInterface * JNIEnv;

VM初始化功能表,如下面的代码所示 。请注意,前三个条目是保留用于将来与COM的兼容性的。此外,我们NULL在函数表的开头附近保留了许多附加条目,因此,例如,可以在FindClass之后而不是在表的末尾添加与类相关的未来JNI操作。

const struct JNINativeInterface ... = {    NULL,    NULL,    NULL,    NULL,    GetVersion,    DefineClass,    FindClass,    FromReflectedMethod,    FromReflectedField,    ToReflectedMethod,    GetSuperclass,    IsAssignableFrom,    ToReflectedField,    Throw,    ThrowNew,    ExceptionOccurred,    ExceptionDescribe,    ExceptionClear,    FatalError,    PushLocalFrame,    PopLocalFrame,    NewGlobalRef,    DeleteGlobalRef,    DeleteLocalRef,    IsSameObject,    NewLocalRef,    EnsureLocalCapacity,    AllocObject,    NewObject,    NewObjectV,    NewObjectA,    GetObjectClass,    IsInstanceOf,    GetMethodID,    CallObjectMethod,    CallObjectMethodV,    CallObjectMethodA,    CallBooleanMethod,    CallBooleanMethodV,    CallBooleanMethodA,    CallByteMethod,    CallByteMethodV,    CallByteMethodA,    CallCharMethod,    CallCharMethodV,    CallCharMethodA,    CallShortMethod,    CallShortMethodV,    CallShortMethodA,    CallIntMethod,    CallIntMethodV,    CallIntMethodA,    CallLongMethod,    CallLongMethodV,    CallLongMethodA,    CallFloatMethod,    CallFloatMethodV,    CallFloatMethodA,    CallDoubleMethod,    CallDoubleMethodV,    CallDoubleMethodA,    CallVoidMethod,    CallVoidMethodV,    CallVoidMethodA,    CallNonvirtualObjectMethod,    CallNonvirtualObjectMethodV,    CallNonvirtualObjectMethodA,    CallNonvirtualBooleanMethod,    CallNonvirtualBooleanMethodV,    CallNonvirtualBooleanMethodA,    CallNonvirtualByteMethod,    CallNonvirtualByteMethodV,    CallNonvirtualByteMethodA,    CallNonvirtualCharMethod,    CallNonvirtualCharMethodV,    CallNonvirtualCharMethodA,    CallNonvirtualShortMethod,    CallNonvirtualShortMethodV,    CallNonvirtualShortMethodA,    CallNonvirtualIntMethod,    CallNonvirtualIntMethodV,    CallNonvirtualIntMethodA,    CallNonvirtualLongMethod,    CallNonvirtualLongMethodV,    CallNonvirtualLongMethodA,    CallNonvirtualFloatMethod,    CallNonvirtualFloatMethodV,    CallNonvirtualFloatMethodA,    CallNonvirtualDoubleMethod,    CallNonvirtualDoubleMethodV,    CallNonvirtualDoubleMethodA,    CallNonvirtualVoidMethod,    CallNonvirtualVoidMethodV,    CallNonvirtualVoidMethodA,    GetFieldID,    GetObjectField,    GetBooleanField,    GetByteField,    GetCharField,    GetShortField,    GetIntField,    GetLongField,    GetFloatField,    GetDoubleField,    SetObjectField,    SetBooleanField,    SetByteField,    SetCharField,    SetShortField,    SetIntField,    SetLongField,    SetFloatField,    SetDoubleField,    GetStaticMethodID,    CallStaticObjectMethod,    CallStaticObjectMethodV,    CallStaticObjectMethodA,    CallStaticBooleanMethod,    CallStaticBooleanMethodV,    CallStaticBooleanMethodA,    CallStaticByteMethod,    CallStaticByteMethodV,    CallStaticByteMethodA,    CallStaticCharMethod,    CallStaticCharMethodV,    CallStaticCharMethodA,    CallStaticShortMethod,    CallStaticShortMethodV,    CallStaticShortMethodA,    CallStaticIntMethod,    CallStaticIntMethodV,    CallStaticIntMethodA,    CallStaticLongMethod,    CallStaticLongMethodV,    CallStaticLongMethodA,    CallStaticFloatMethod,    CallStaticFloatMethodV,    CallStaticFloatMethodA,    CallStaticDoubleMethod,    CallStaticDoubleMethodV,    CallStaticDoubleMethodA,    CallStaticVoidMethod,    CallStaticVoidMethodV,    CallStaticVoidMethodA,    GetStaticFieldID,    GetStaticObjectField,    GetStaticBooleanField,    GetStaticByteField,    GetStaticCharField,    GetStaticShortField,    GetStaticIntField,    GetStaticLongField,    GetStaticFloatField,    GetStaticDoubleField,    SetStaticObjectField,    SetStaticBooleanField,    SetStaticByteField,    SetStaticCharField,    SetStaticShortField,    SetStaticIntField,    SetStaticLongField,    SetStaticFloatField,    SetStaticDoubleField,    NewString,    GetStringLength,    GetStringChars,    ReleaseStringChars,    NewStringUTF,    GetStringUTFLength,    GetStringUTFChars,    ReleaseStringUTFChars,    GetArrayLength,    NewObjectArray,    GetObjectArrayElement,    SetObjectArrayElement,    NewBooleanArray,    NewByteArray,    NewCharArray,    NewShortArray,    NewIntArray,    NewLongArray,    NewFloatArray,    NewDoubleArray,    GetBooleanArrayElements,    GetByteArrayElements,    GetCharArrayElements,    GetShortArrayElements,    GetIntArrayElements,    GetLongArrayElements,    GetFloatArrayElements,    GetDoubleArrayElements,    ReleaseBooleanArrayElements,    ReleaseByteArrayElements,    ReleaseCharArrayElements,    ReleaseShortArrayElements,    ReleaseIntArrayElements,    ReleaseLongArrayElements,    ReleaseFloatArrayElements,    ReleaseDoubleArrayElements,    GetBooleanArrayRegion,    GetByteArrayRegion,    GetCharArrayRegion,    GetShortArrayRegion,    GetIntArrayRegion,    GetLongArrayRegion,    GetFloatArrayRegion,    GetDoubleArrayRegion,    SetBooleanArrayRegion,    SetByteArrayRegion,    SetCharArrayRegion,    SetShortArrayRegion,    SetIntArrayRegion,    SetLongArrayRegion,    SetFloatArrayRegion,    SetDoubleArrayRegion,    RegisterNatives,    UnregisterNatives,    MonitorEnter,    MonitorExit,    GetJavaVM,    GetStringRegion,    GetStringUTFRegion,    GetPrimitiveArrayCritical,    ReleasePrimitiveArrayCritical,    GetStringCritical,    ReleaseStringCritical,    NewWeakGlobalRef,    DeleteWeakGlobalRef,    ExceptionCheck,    NewDirectByteBuffer,    GetDirectBufferAddress,    GetDirectBufferCapacity,    GetObjectRefType  };
View Code

请注意,函数表可以在所有JNI接口指针之间共享。

 二、JNI 接口基本方法(JNI Base Api)

1. GetVersion (获取版本信息)

jint GetVersion(JNIEnv *env);

返回JNI的版本号。

参数:

env: jni接口指针  

返回值:

返回一个值,其中高位为major版本号返回,低位为minor版本号。

在 JDK/JRE 1.1中返回 0x00010001

在 JDK/JRE 1.2中返回 0x00010002

在 JDK/JRE 1.4中返回 0x00010004

在 JDK/JRE 1.6中返回 0x00010006

常量:

SINCE JDK/JRE 1.2:

#define JNI_VERSION_1_1 0x00010001 #define JNI_VERSION_1_2 0x00010002 /* Error codes */ #define JNI_EDETACHED (-2) /* thread detached from the VM */ #define JNI_EVERSION (-3) /* JNI version error

SINCE JDK/JRE 1.4:

#define JNI_VERSION_1_4 0x00010004

SINCE JDK/JRE 1.6:

#define JNI_VERSION_1_6 0x00010006

使用实例:

jint version = env->GetVersion();

2. FindClass(发现Java类)

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

在JDK 1.1发行版中,这个函数加载本地定义的类(locally-defined class), 它搜索在由环境变量 CLASSPATH 目录下的子目录和zip文件中搜索指定的类名。

从JDK 1.2发行版之后,Java安全模型允许非本地系统类也可以加载和调用本地方法。FindClass 函数会使用与当前本地方法关联的ClassLoader, 并用它来加载本地方法指定的class。如果本地方法属于系统类(system class),则没有ClassLoader会被调用。否则,将使用正确的ClassLoader来加载(load)和链接(link)指定名称的类。

从JDK 1.2发行版之后,当通过 Invocation 接口来调用 FindClass 函数,将没有当前的本地方法或与之关联的ClassLoader。这种情况下,会使用 ClassLoader.getSystemClassLoader 来替代。这个ClassLoader 是虚拟机用来创建应用(applications)的,它有能力定位到 java.class.path 参数下的所有类。

第二个 name 参数,使用全称类名或数组类型签名(array type signature)。例如,String类的全称类名为:

"java/lang/String" 

而Object数组类型的使用:

"[Ljava/lang/Object;" 

注意:一定要注意分隔符不是 . 而是 / ,不要写错了。

参数:

env:JNI接口指针 

name:全称的类名(包名以 / 作为分隔符, 然后紧跟着类名),如果名字以 [开头(数组签名标识符),则返回一个数组的类,这个字符串也是MUTF-8。 

返回值:

指定名称的类的对象(a class object),或者在没有找到对应类时返回 NULL

抛出异常:

ClassFormatError :如果class内容不是一个有效的class文件。 

ClassCircularityError:如果class或interface是它自己的父类或父接口,造成循环层级关系。 

OutOfMemoryError:如果系统在载入的过程中内存不足。

NoClassDefFoundError:如果指定的类或接口没有被找到。(当name传null或超长时也会抛出这个异常) 

使用实例:

// Start thread which receives commands from the SA. jclass threadClass = env->FindClass("java/lang/Thread"); if (threadClass == NULL) stop("Unable to find class java/lang/Thread"); jstring threadName = env->NewStringUTF("Serviceability Agent Command Thread"); if (threadName == NULL) stop("Unable to allocate debug thread name"); jmethodID ctor = env->GetMethodID(threadClass, "
", "(Ljava/lang/String;)V"); if (ctor == NULL) stop("Unable to find appropriate constructor for java/lang/Thread"); // Allocate thread object jthread thr = (jthread) env->NewObject(threadClass, ctor, threadName);  

以上代码来之 openJDK 源码 中的 /hotspot/agent/src/share/native/jvmdi/sa.cpp

 3. GetSuperclass (获取父类)

jclass GetSuperclass(JNIEnv *env, jclass clazz);

只要传入的 clazz 参数不是 java/lang/Object 则返回该类的父类。 

如果传入的 clazz 参数是 java/lang/Object 则返回NULL,因为它没有父类。当传入的是一个接口,而不是类时,也返回 NULL 。

参数:

env:JNI接口指针 

clazz: Java类对象(java class object) 

返回值:

返回传入的 clazz 的父类,或 NULL .

使用实例:

jclass clazz = env->GetObjectClass(thiz); clazz = env->GetSuperclass(clazz); jfieldID __state = env->GetFieldID(clazz, "__state", "J");  

以上代码来至:https://github.com/liucheng98/mesos-0.22.0/blob/5cfd2c36c0e8361fa2e2d9b6f191a738d22a9cfd/src/java/jni/org_apache_mesos_state_LogState.cpp

4. IsAssignableFrom (检查类是否能转型)

jboolean IsAssignableFrom(JNIEnv *env, jclass class1, jclass clazz2);

检查 clazz1 的对象是否能被安全的转型(cast)为 clazz2

参数:

env:JNI接口指针 

clazz1:第一个class参数(需要转型的类) 
clazz2:第二个class参数(转型的目标类) 

返回值:

如果是以下情况则返回 JNI_TRUE :

clazz1 和 clazz2 指向同一个java类 

clazz1 是 clazz2 的子类。(向上转型是安全的) 
clazz1 是 clazz2(接口)的实现类。(也属于向上转型) 

使用实例:

jclass listInterface = env->FindClass("java/util/List") jclass arrayListClass = env->FindClass("java/util/ArrayList") jboolean isSafe = env->IsAssignableFrom(arrayListClass, listInterface); // isSafe: true; isSafe = env->IsAssignableFrom(listInterface, arrayListClass); // isSafe: false;

三、 JNI 异常方法 (JNI Exception) 

1. Throw (抛出异常)

jint Throw(JNIEnv *env, jthrowable obj);  

触发一个 java.lang.Throwable 对象的异常被抛出。

参数:

env:JNI接口指针 

obj: java.lang.Throwable 对象 

返回值:

成功则返回0, 失败时返回赋值 

抛出异常:

抛出 java.lang.Throwable 对象 

使用实例:

jthrowable exception = env->ExceptionOccurred(); if (exception) { env->ExceptionClear(); detach_internal(env, this_obj); env->Throw(exception); return; }  

以上代码来至 OpenJDK 源码 /hotspot/agent/src/os/solaris/proc/saproc.cpp

2. ThrowNew (构造一个异常对象并抛出)

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

Exception对象的构造器函数,message为异常的错误消息,clazz为异常的类。

参数:

env:JNI接口指针 

clazz: java.lang.Throwable 的子类 
message: 用于创建 java.lang.Throwable 对象时传入的错误消息。这个是字符串是MUTF-8编码。 

返回值: 

成功则返回0, 失败时返回赋值 

抛出异常: 

抛出刚构造出来的 java.lang.Throwable 对象 

使用实例:

env->ThrowNew(env->FindClass("sun/jvm/hotspot/debugger/DebuggerException"), errMsg);

3. ExceptionOccurred (检查是否有异常被抛出)

jthrowable ExceptionOccurred(JNIEnv *env);

检查是否有异常被抛出。这个异常在本地方法调用 ExceptionClear() 方法或被Java代码处理这个异常之前都会保持在被抛出状态。

参数:

env:JNI接口指针 

返回值:

返回过程中抛出的异常,或没有异常被抛出时返回 NULL 。

使用实例:

jthrowable exception = env->ExceptionOccurred(); if (exception) { env->ExceptionClear(); detach_internal(env, this_obj); env->Throw(exception); return; }

以上代码来至 OpenJDK 源码 /hotspot/agent/src/os/solaris/proc/saproc.cpp

4. ​ExceptionDescribe (打印异常的stack trace)

void ExceptionDescribe(JNIEnv *env);  

打印一个异常的stack trace到系统的错误输出,例如 stderr 这是为了调试提供便利。

参数:

env:JNI接口指针 

使用实例:

jthrowable exc = safe_ExceptionOccurred(env); if (exc) { env->DeleteLocalRef(exc); env->ExceptionDescribe(); env->ExceptionClear(); }  

以上代码来至:OpenJDK 源码中的 /jdk/src/windows/native/sun/windows/awt_Object.cpp

5. ExceptionClear (清理所有即将抛出的异常)

void ExceptionClear(JNIEnv *env);

清理任何即将抛出的异常。如果没有异常被抛出,则不起任何作用。

参数:

env:JNI接口指针 

使用实例:

jthrowable exc = safe_ExceptionOccurred(env); if (exc) { env->DeleteLocalRef(exc); env->ExceptionDescribe(); env->ExceptionClear(); }  

以上代码来至:OpenJDK 源码中的 /jdk/src/windows/native/sun/windows/awt_Object.cpp

6. FatalError (抛出一个严重的错误)

void FatalError(JNIEnv *env, const char *msg);

抛出一个严重错误,并不希望虚拟机恢复。 

参数:

env:JNI接口指针 

msg : 错误消息,这个字符串为MUTF-8编码 

使用实例:

env->CallVoidMethod(currentThread, setThreadName, threadName) ; if( env->ExceptionCheck() ) { env->ExceptionDescribe() ; env->FatalError("setting thread name failed: could not start reading thread"); return 0L ; }  

以上代码来至:https://github.com/tnarnold/netsnmpj/blob/3153c3e9297dd7de7db9d1a65c97f77937ae147b/netsnmpj-preliminary/native/nativeThread.cc

7. ExceptionCheck (快速检查是否有异常被抛出)

jboolean ExceptionCheck(JNIEnv *env);

这是一个快速函数用于检查是否有被抛出的异常,而不创建一个这个异常的局部引用。

参数:

env:JNI接口指针 

返回值: 

有一个即将被抛出的异常时返回 JNI_TURE ,没有则返回 JNI_FALSE 

使用实例:

env->CallVoidMethod(thread, runId); if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); // handle exception }  

以上代码来至:OpenJDK 源码中的 /jdk/src/windows/native/sun/windows/awt_Toolkit.cpp

 

转载地址:http://rzfsx.baihongyu.com/

你可能感兴趣的文章
Android利用文本分割拼接开发一个花藤文字生成
查看>>
哈夫曼树的实现
查看>>
12-18Windows窗体应用小程序之记事本(1)
查看>>
毕业论文一次性修改所有字母和数字的字体
查看>>
结构体:HASH表模板
查看>>
[转]理解Linux文件系统之inode
查看>>
在i3 Cpu上允许64位系统
查看>>
视频编解码学习之五:差错控制及传输
查看>>
Postman教程
查看>>
python模块--os模块
查看>>
HSSFRow获取单元格方法与区别
查看>>
洛谷 1365 WJMZBMR打osu! / Easy
查看>>
删除UINavigationItem上的BarButtonItem
查看>>
数据分析相关模块
查看>>
Python数据结构1-----基本数据结构和collections系列
查看>>
SQL Denali-FileTable
查看>>
C# 图像处理:复制屏幕到内存中,拷屏操作
查看>>
PHP微信支付流程
查看>>
linux下单节点oracle数据库间ogg搭建
查看>>
PLSQL Developer软件使用大全
查看>>