Android Studio3.0开发JNI流程------JNI函数

JNI函数

    本章为JNI函数提供参考信息。其中列出了全部JNI函数,同时也给出了JNI函数表的准确布局。注意:“必须”一词用于约束JNI编程人员。例如,当说明某个JNI函数必须接收非空对象时,就应确保不要向该JNI函数传递NULL值。这时,JNI实现将无需在该JNI函数中执行NULL指针检查。

接口函数表

    每个函数均可通过JNIEnv参数以固定偏移量进行访问。JNIEnv的类型是一个指针,指向存储全部JNI函数指针的结构。注意:前三项留作将来与COM兼容。此外,我们在函数表开头部分也留出来多个NULL项,从而可将将来与类有关的JNI操作添加到FindClass后面,而非函数表的末尾。注意,函数表可在所有JNI接口指针间共享。

const struct JNINativeInterface ... = {
    NULL,
    NULL,
    NULL,
    NULL,
    GetVersion,

    DefineClass,
    FindClass,
    NULL,
    NULL,
    NULL,
    GetSuperclass,
    IsAssignableFrom,
    NULL,

    Throw,
    ThrowNew,
    ExceptionOccurred,
    ExceptionDescribe,
    ExceptionClear,
    FatalError,
    NULL,
    NULL,

    NewGlobalRef,
    DeleteGlobalRef,
    DeleteLocalRef,
    IsSameObject,
    NULL,
    NULL,
    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,
};

版本信息

GetVersion( )返回本地方法接口的版本。

jint GetVersion(JNIEnv *env);

参数 :
env为JNI接口指针

返回值:
高16位返回主版本号,低16位返回次版本号
在JDK1.1 中,GetVersion()返回0x00010001

类操作

DefineClass( )从原始类数据的缓冲区中加载类。

jclass DefineClass(JNIEnv *env, jobject loader, const jbyte *buf, jsize bufLen);

参数:
env:JNI 接口指针。
loader:分派给所定义的类的类加载器。
buf:包含.class文件数据的缓冲区。
bufLen:缓冲区长度。

返回值:
返回Java类对象如果出错则返回NULL

抛出的异常:
- ClassFormatError:如果类数据指定的类无效。
- ClassCircularityError:如果类或接口是自身的超类或超接口。
- OutOfMemoryError:如果系统内存不足。

FindClass( ) 该函数用于加载本地定义的类。它将搜索由CLASSPATH环境变量为具有指定名称的类所指定的目录和zip文件。

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

参数:
env:JNI接口指针。
name:类全名(即包名后跟类名,之间由“/”分隔)。如果该名称以“[”(数组签名字符)打头,则返回一个数组类。

返回值:
返回类对象全名。如果找不到该类,则返回NULL。

抛出:
- ClassFormatError:如果类数据指定的类无效。
- ClassCircularityError:如果类或接口是自身的超类或超接口。
- NoClassDefFoundError:如果找不到所请求的类或接口的定义。
- OutOfMemoryError:如果系统内存不足。

GetSuperclass( ) 如果clazz代表类而非类object,则该函数返回由clazz所指定的类的超类。如果clazz指定类object或代表某个接口,则该函数返回NULL。

jclass GetSuperclass(JNIEnv *env, jclass clazz);

参数:
env:JNI接口指针。
clazz:Java类对象。

返回值:
由clazz所代表的类的超类或NULL

IsAssignableFrom ( ) 确定clazz1的对象是否可安全地强制转换为clazz2。

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

参数:
env:JNI接口指针。
clazz1:第一个类参数。
clazz2:第二个类参数。

返回值:
下列某个情况为真时返回JNI_TRUE
第一及第二个类参数引用同一个Java类
第一个类是第二个类的子类
第二个类是第一个类的某个接口

异常

Throw( ) 抛出java.lang.Throwable对象。

jint Throw(JNIEnv *env, jthrowable obj);

参数:
env:JNI接口指针。
obj:java.lang.Throwable对象。

返回值:
成功时返回0,失败时返回负数。

抛出:
java.lang.Throwable对象obj

ThrowNew( )利用指定类的消息(由message指定)构造异常对象并抛出该异常。

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

参数:
env:JNI接口指针。
clazz:java.lang.Throwable的子类。
message:用于构造java.lang.Throwable对象的消息。

返回值:
成功时返回0,失败时返回负数。

抛出:
新构造的java.lang.Throwable对象。

ExceptionOccurred( ) 确定是否某个异常正被抛出。在平台相关代码调用ExceptionClear()或Java代码处理该异常前,异常将始终保持抛出状态。

jthrowable ExceptionOccurred(JNIEnv *env);

参数:
env:JNI接口指针。

返回值:
返回正被抛出的异常对象,如果当前无异常被抛出,则返回NULL

ExceptionDescribe( ) 将异常及堆栈的回溯输出到系统错误报告信道(例如 stderr)。该例程可便利调试操作。

void ExceptionDescribe(JNIEnv *env);

参数:
env:JNI接口指针。

ExceptionClear( ) 清除当前抛出的任何异常。如果当前无异常,则此例程不产生任何效果。

void ExceptionClear(JNIEnv *env);

参数:
env:JNI接口指针。

FatalError( )抛出致命错误并且不希望虚拟机进行修复。该函数无返回值。

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

参数:
env:JNI接口指针。
msg:错误消息。

全局及局部引用

NewGlobalRef( ) 创建obj参数所引用对象的新全局引用。obj参数既可以是全局引用,也可以是局部引用。全局引用通过调用DeleteGlobalRef()来显式撤消。

jobject NewGlobalRef(JNIEnv *env, jobject obj);

参数:
env:JNI接口指针。
obj:全局或局部引用。

返回值:
返回全局引用。如果系统内存不足则返回NULL

DeleteGlobalRef( ) 删除globalRef所指向的全局引用。

void DeleteGlobalRef(JNIEnv *env, jobject globalRef);

参数:
env:JNI接口指针。
globalRef:全局引用。

DeleteLocalRef( ) 删除localRef所指向的局部引用。

void DeleteLocalRef(JNIEnv *env, jobject localRef);

参数:
env:JNI接口指针。
localRef:局部引用。

对象操作

AllocObject( ) 分配新Java对象而不调用该对象的任何构造函数。返回该对象的引用。clazz参数务必不要引用数组类。

jobject AllocObject(JNIEnv *env, jclass clazz);

参数:
env:JNI接口指针。
clazz:Java类对象。

返回值:
返回Java对象。如果无法构造该对象,则返回NULL

抛出:
InstantiationException:如果该类为一个接口或抽象类
OutOfMemoryError:如果系统内存不足

NewObject( ) NewObjectA( ) NewObjectV( ) 构造新Java对象。

jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...);
jobject NewObjectA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
jobject NewObjectV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

方法ID指示应调用的构造函数方法。该ID必须通过调用GetMethodID( )获得,且调用时的方法名必须为init,而返回类型必须为void(V)。clazz参数务必不要引用数组类。

NewObject( )
编程人员应将传递给构造函数的所有参数紧跟着放在methodID参数的后面。NewObject( )收到这些参数后,将把它们传给编程人员所要调用的Java方法。

NewObjectA( )
编程人员应将传递给构造函数的所有参数放在jvalues类型的数组args中,该数组紧跟着放在methodID参数的后面。NewObject()收到数组中的这些参数后,将把它们传给编程人员所要调用的Java方法。

NewObjectV( )
编程人员应将传递给构造函数的所有参数放在va_list类型的参数args中,该参数紧跟着放在methodID参数的后面。NewObject()收到这些参数后,将把它们传给编程人员所要调用的Java方法。

参数:
env:JNI接口指针。
clazz:Java类对象。
methodID:构造函数的方法ID。

NewObject 的其它参数:
传给构造函数的参数。

NewObjectA的其它参数:
args:传给构造函数的参数数组

NewObjectV的其它参数:
args:传给构造函数的参数va_list

返回值:
返回Java对象,如果无法构造该对象,则返回NULL

抛出:
InstantiationException:如果该类为接口或抽象类
OutOfMemoryError:如果系统内存不足

构造函数抛出的任何异常。

GetObjectClass( ) 返回对象的类。

jclass GetObjectClass(JNIEnv *env, jobject obj);

参数:
env:JNI接口指针。
obj:Java对象(不能为NULL)。

返回值:
返回Java类对象

IsInstanceOf( ) 测试对象是否为某个类的实例。

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

参数:
env:JNI接口指针。
obj:Java对象。
clazz:Java类对象。

返回值:
如果可将obj强制转换为clazz,则返回JNI_TRUE。否则返回JNI_FALSE。NULL对象可强制转换为任何类

IsSameObject( ) 测试两个引用是否引用同一Java对象。

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

参数:
env:JNI接口指针。
ref1:Java对象。
ref2:Java对象。

返回值:
如果ref1和ref2引用同一Java对象或均为NULL,则返回JNI_TRUE。否则返回JNI_FALSE

访问对象的域

GetFieldID( )

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

返回类的实例(非静态)域的域ID。该域由其名称及签名指定。访问器函数的Get[type]FieldSet[type]Field系列使用域ID检索
对象域。GetFieldID( )将未初始化的类初始化。GetFieldID( )不能用于获取数组的长度域。应使GetArrayLength( )

参数:
env:JNI接口指针。
clazz:Java类对象。
name: 0终结的UTF-8字符串中的域名。
sig:0终结的UTF-8字符串中的域签名。

返回值:
域ID。如果操作失败,则返回NULL。

抛出:
NoSuchFieldError:如果找不到指定的域
ExceptionInInitializerError:如果由于异常而导致类初始化程序失败
OutOfMemoryError:如果系统内存不足

Get[type]Field例程

NativeType Get[type]Field(JNIEnv *env, jobject obj, jfieldID fieldID);

该访问器例程系列返回对象的实例(非静态)域的值。要访问的域由通过调用GetFieldID( )而得到的域ID指定。

参数:
env:JNI接口指针。
obj:Java对象(不能为 NULL)。
fieldID:有效的域ID。

返回值:
域的内容

下表说明了Get[type]Field例程名及结果类型。应将Get[type]Field中的type替换为域的Java类型(或使用表中的某个实际例程名),然后将NativeType替换为该例程对应的本地类型。

Get[type]Field例程名 本地类型
GetObjectField( ) jobject
GetBooleanField( ) jboolean
GetByteField( ) jbyte
GetCharField( ) jchar
GetShortField( ) jshort
GetIntField( ) jint
GetLongField( ) jlong
GetFloatField( ) jfloat
GetDoubleField( ) jdouble

Set[type]Field例程

void Set[type]Field(JNIEnv *env, jobject obj, jfieldID fieldID, NativeType value);

该访问器例程系列设置对象的实例(非静态)域的值。要访问的域由通过调用SetFieldID( )而得到的域ID指定。

参数:
env:JNI接口指针。
obj:Java对象(不能为NULL)。
fieldID:有效的域ID。
value:域的新值。

下表说明了Set[type]Field例程名及结果类型。应将Set[type]Field中的type替换为域的Java类型(或使用表中的某个实际例程名),然后将NativeType替换为该例程对应的本地类型。

Set[type]Field例程名 本地类型
Set[type]Field例程名 本地类型
SetObjectField( ) jobject
SetBooleanField( ) jboolean
SetByteField( ) jbyte
SetCharField( ) jchar
SetShortField( ) jshort
SetIntField( ) jint
SetLongField( ) jlong
SetFloatField( ) jfloat
SetDoubleField( ) jdouble

调用实例方法

GetMethodID( )

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

返回类或接口实例(非静态)方法的方法ID。方法可在某个clazz的超类中定义,也可从clazz继承。该方法由其名称和签名决定。GetMethodID( )可使未初始化的类初始化。要获得构造函数的方法ID,应将[init]作为方法名,同时将void (V)作为返回类型。

参数:
env:JNI接口指针。
clazz:Java类对象。
name:0终结的UTF-8字符串中的方法名。
sig:0终结的UTF-8字符串中的方法签名。

返回值:
方法ID,如果找不到指定的方法,则为NULL

抛出:
NoSuchMethodError:如果找不到指定方法
ExceptionInInitializerError:如果由于异常而导致类初始化程序失败
OutOfMemoryError:如果系统内存不足

Call[type]Method( ),Call[type]MethodA( ),Call[type]MethodV( )例程

NativeType Call[type]Method(JNIEnv *env, jobject obj, jmethodID methodID, ...);
NativeType Call[type]MethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);
NativeType Call[type]MethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args);

这三个操作的方法用于从本地方法调用Java实例方法。它们的差别仅在于向其所调用的方法传递参数时所用的机制。这三个操作将根据所指定的方法ID调用Java对象的实例(非静态)方法。参数methodID必须通过调用GetMethodID( )来获得。当这些函数用于调用私有方法和构造函数时,方法ID必须从obj的真实类派生而来,而不应从其某个超类派生。

参数:
env:JNI接口指针。
obj:Java对象。
methodID:方法ID。

Call[type]Method例程的其它参数:
要传给Java方法的参数

Call[type]MethodA例程的其它参数:
args:参数数组

Call[type]MethodV例程的其它参数:
args:参数的va_list

返回值:
返回调用Java方法的结果

抛出:
执行Java方法时抛出的异常
Call[type]Method例程

编程人员应将要传给方法的所有参数紧跟着放在methodID参数之后。Call[type]Method例程接受这些参数并将其传给编程人员所要调用的Java方法。

Call[type]MethodA例程

编程人员应将要传给方法的所有参数放在紧跟在methodID参数之后的jvalues类型数组args中。Call[type]MethodA routine接受这些数组中的参数并将其传给编程人员所要调用的Java方法。

Call[type]MethodV 例程

编程人员将方法的所有参数放在紧跟着在methodID参数之后的va_list类型参数变量中。Call[type]MethodV routine接受这些参数并将其传给编程人员所要调用的Java方法。

下表根据结果类型说明了各个方法调用例程。用户应将Call[type]Method中的type替换为所调用方法的Java类型(或使用表中的实际方法调用例程名),同时将NativeType替换为该例程相应的本地类型。

Call[type]Method例程名 本地类型
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

CallNonvirtual[type]Method,CallNonvirtual[type]MethodA,CallNonvirtual[type]MethodV例程

NativeType CallNonvirtual[type]Method(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
NativeType CallNonvirtual[type]MethodA(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args);
NativeType CallNonvirtual[type]MethodV(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args);

这些操作根据指定的类和方法ID调用某Java对象的实例(非静态)方法。参数methodID必须通过调用clazz类的GetMethodID( )获得。CallNonvirtual[type]Method和Call[type]Method例程系列并不相同。Call[type]Method例程根据对象的类调用方法,而CallNonvirtual[type]Method例程则根据获得方法ID的(由clazz参数指定)类调用方法。方法ID必须从对象的真实类或其某个超类获得

参数:
env:JNI接口指针。
clazz:Java类。
obj: Java对象。
methodID:方法ID。

CallNonvirtual[type]Method例程的其它参数:
要传给Java方法的参数

CallNonvirtual[type]MethodA例程的其它参数:
args:参数数组

CallNonvirtual[type]MethodV例程的其它参数:
args:参数的va_list

返回值:
调用Java方法的结果

抛出:
执行Java方法时所抛出的异常

CallNonvirtual[type]Method例程

编程人员应将要传给方法的所有参数紧跟着放在methodID参数之后。CallNonvirtual[type]Method routine接受这些参数并将其传给编程人员所要调用的Java方法。

CallNonvirtual[type]MethodA例程

编程人员应将要传给方法的所有参数放在紧跟在methodID参数之后的jvalues类型数组args中。
CallNonvirtual[type]MethodA routine接受这些数组中的参数并将其传给编程人员所要调用的Java方法。

CallNonvirtual[type]MethodV例程

编程人员应将要传给方法的所有参数放在紧跟在methodID参数之后的va_list类型参数args中。CallNonvirtualMethodV routine接受这些参数并将其传给编程人员所要调用的Java方法。

下表根据结果类型说明了各个方法调用例程。用户应将CallNonvirtual[type]Method中的type替换为所调用方法的Java类型(或使用表中的实际方法调用例程名),同时将NativeType替换为该例程相应的本地类型。

CallNonvirtual[type]Method例程名 本地类型
CallNonvirtualVoidMethod( ) CallNonvirtualVoidMethodA( ) CallNonvirtualVoidMethodV( ) void
CallNonvirtualObjectMethod( ) CallNonvirtualObjectMethodA( ) CallNonvirtualObjectMethodV( ) jobject
CallNonvirtualBooleanMethod( ) CallNonvirtualBooleanMethodA( ) CallNonvirtualBooleanMethodV( ) jboolean
CallNonvirtualByteMethod( ) CallNonvirtualByteMethodA( ) CallNonvirtualByteMethodV( ) jbyte
CallNonvirtualCharMethod( ) CallNonvirtualCharMethodA( ) CallNonvirtualCharMethodV( ) jchar
CallNonvirtualShortMethod( ) CallNonvirtualShortMethodA( ) CallNonvirtualShortMethodV( )
CallNonvirtualIntMethod( ) CallNonvirtualIntMethodA( ) CallNonvirtualIntMethodV( ) jint
CallNonvirtualLongMethod( ) CallNonvirtualLongMethodA( ) CallNonvirtualLongMethodV( ) jlong
CallNonvirtualFloatMethod( ) CallNonvirtualFloatMethodA( ) CallNonvirtualFloatMethodV( ) jfloat
CallNonvirtualDoubleMethod( ) CallNonvirtualDoubleMethodA( ) CallNonvirtualDoubleMethodV( ) jdouble

访问静态域

GetStaticFieldID( )

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

返回类的静态域的域ID。域由其名称和签名指定。GetStatic[type]Field和SetStatic[type]Field访问器函数系列使用域ID检索静态域。GetStaticFieldID()将未初始化的类初始化。

参数:
env:JNI接口指针。
clazz:Java类对象。
name: 0终结的UTF-8字符串中的静态域名。
sig:0终结的UTF-8字符串中的域签名。

返回值:
域ID。如果找不到指定的静态域,则为NULL
抛出:
NoSuchFieldError:如果找不到指定的静态域
ExceptionInInitializerError:如果由于异常而导致类初始化程序失败
OutOfMemoryError:如果系统内存不足

GetStatic[type]Field例程

NativeType GetStatic[type]Field(JNIEnv *env, jclass clazz, jfieldID fieldID);

该访问器例程系列返回对象的静态域的值。要访问的域由通过调用GetStaticFieldID()而得到的域ID指定。

参数:
env:JNI接口指针。
clazz:Java类对象。
fieldID:静态域ID。

返回值:
静态域的内容

下表说明了GetStatic[type]Field例程名及结果类型。应将GetStatic[type]Field中的type替换为域的Java类型(或使用表中的某个实际例程名),然后将NativeType替换为该例程对应的本地类型。

GetStatic[type]Field例程名 本地类型
GetStaticObjectField( ) jobject
GetStaticBooleanField( ) jboolean
GetStaticByteField( ) jbyte
GetStaticCharField( ) jchar
GetStaticShortField( ) jshort
GetStaticIntField( ) jint
GetStaticLongField( ) jlong
GetStaticFloatField( ) jfloat
GetStaticDoubleField( ) jdouble

SetStatic[type]Field例程

void SetStatic[type]Field(JNIEnv *env, jclass clazz, jfieldID fieldID, NativeType value);

该访问器例程系列设置对象的静态域的值。要访问的域由通过调用GetStaticFieldID()而得到的域ID指定。

参数:
env:JNI接口指针。
clazz:Java类对象。
fieldID:静态域ID。
value:域的新值。

下表说明了SetStatic[type]Field例程名及结果类型。应将SetStatic[type]Field中的type替换为域的Java类型(或使用表中的某个实际例程名),然后将NativeType替换为该例程对应的本地类型。

SetStatic[type]Field例程名 本地类型
SetStaticObjectField( ) jobject
SetStaticBooleanField( ) jboolean
SetStaticByteField( ) jbyte
SetStaticCharField( ) jchar
SetStaticShortField( ) jshort
SetStaticIntField( ) jint
SetStaticLongField( ) jlong
SetStaticFloatField( ) jfloat
SetStaticDoubleField( ) jdouble

调用静态方法

GetStaticMethodID( ) 返回类的静态方法的方法ID。方法由其名称和签名指定。GetStaticMethodID( )将未初始化的类初始化

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

参数:
env:JNI接口指针。
clazz:Java类对象。
name:0终结UTF-8字符串中的静态方法名。
sig:0终结UTF-8字符串中的方法签名。

返回值:
方法ID,如果操作失败,则为NULL

抛出:
NoSuchMethodError:如果找不到指定的静态方法
ExceptionInInitializerError:如果由于异常而导致类初始化程序失败
OutOfMemoryError:如果系统内存不足

CallStatic[type]Method,CallStatic[type]MethodA,CallStatic[type]MethodV( ) 例程

NativeType CallStatic[type]Method(JNIEnv *env, jclass clazz, jmethodID methodID, ...);
NativeType CallStatic[type]MethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
NativeType CallStatic[type]MethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

这些操作将根据指定的方法ID调用Java对象的静态方法。methodID参数必须通过调用GetStaticMethodID()得到。方法ID必须从clazz派生,而不能从其超类派生。

参数:
env:JNI接口指针。
clazz:Java类对象。
methodID:静态方法ID。

CallStatic[type]Method例程的其它参数:
要传给静态方法的参数

CallStatic[type]MethodA例程的其它参数:
args:参数数组

CallStatic[type]MethodV例程的其它参数:
args:参数的va_list

返回值:
返回调用静态Java方法的结果

抛出:
执行Java方法时抛出的异常

CallStatic[type]Method例程

编程人员应将要传给方法的所有参数紧跟着放在methodID参数之后。CallStatic[type]Method routine接受这些参数并将其传给编程人员所要调用的Java方法。

CallStatic[type]MethodA例程

编程人员应将要传给方法的所有参数放在紧跟在methodID参数之后的jvalues类型数组args中。CallStaticMethodA routine接受这些数组中的参数并将其传给编程人员所要调用的Java方法。

CallStatic[type]MethodV例程

编程人员应将要传给方法的所有参数放在紧跟在methodID参数之后的va_list类型参数args中。CallStaticMethodV routine接受这些参数并将其传给编程人员所要调用的Java方法。

下表根据结果类型说明了各个方法调用例程。用户应将CallStatic[type]Method中的type替换为所调用方法的Java类型(或使用表中的实际方法调用例程名),同时将NativeType替换为该例程相应的本地类型。

CallStatic[type]Method例程名 本地类型
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

字符串操作

NewString( ) 利用Unicode字符数组构造新的java.lang.String对象。

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

参数:
env:JNI接口指针。
unicodeChars:指向Unicode字符串的指针。
len:Unicode字符串的长度。

返回值:
Java字符串对象。如果无法构造该字符串,则为NULL

抛出:
OutOfMemoryError:如果系统内存不足

GetStringLength( ) 返回Java字符串的长度(Unicode字符数)。

jsize GetStringLength(JNIEnv *env, jstring string);

参数:
env:JNI接口指针。
string:Java字符串对象。

返回值:
Java 字符串的长度

GetStringChars( ) 返回指向字符串的Unicode字符数组的指针。该指针在调用ReleaseStringchars()前一直有效。如果isCopy非空,则在复制完成后将*isCopy设为JNI_TRUE。如果没有复制,则设为JNI_FALSE。

const jchar * GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy);

参数:
env:JNI接口指针。
string:Java字符串对象。
isCopy:指向布尔值的指针。

返回值:
指向Unicode字符串的指针,如果操作失败,则返回NULL

ReleaseStringChars( ) 通知虚拟机平台相关代码无需再访问chars。参数chars是一个指针,可通过GetStringChars( )从string获得。

void ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars);

参数:
env:JNI接口指针。
string:Java字符串对象。
chars:指向Unicode字符串的指针。

NewStringUTF( ) 利用UTF-8字符数组构造新java.lang.String对象。

jstring NewStringUTF(JNIEnv *env, const char *bytes);

参数:
env:JNI接口指针。如果无法构造该字符串,则为NULL。
bytes:指向UTF-8字符串的指针。

返回值:
Java字符串对象。如果无法构造该字符串,则为NULL

抛出:
OutOfMemoryError:如果系统内存不足

GetStringUTFLength( ) 以字节为单位返回字符串的UTF-8长度。

jsize GetStringUTFLength(JNIEnv *env, jstring string);

参数:
env:JNI接口指针。
string:Java字符串对象。

返回值:
返回字符串的UTF-8长度

GetStringUTFChars( ) 返回指向字符串的UTF-8字符数组的指针。该数组在被ReleaseStringUTFChars( )释放前将一直有效。如果isCopy不是NULL,*isCopy在复制完成后即被设为JNI_TRUE。如果未复制,则设为JNI_FALSE。

const char* GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);

参数:
env:JNI接口指针。
string:Java字符串对象。
isCopy:指向布尔值的指针。

返回值:
指向UTF-8字符串的指针。如果操作失败,则为NULL

ReleaseStringUTFChars( ) 通知虚拟机平台相关代码无需再访问utf。utf参数是一个指针,可利用GetStringUTFChars( )从string获得。

void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf);

参数:
env:JNI接口指针。
string:Java字符串对象。
utf:指向UTF-8字符串的指针。

数组操作

GetArrayLength( ) 返回数组中的元素数。

jsize GetArrayLength(JNIEnv *env, jarray array);

参数:
env:JNI接口指针。
array:Java数组对象。

返回值:
数组的长度

NewObjectArray( ) 构造新的数组,它将保存类elementClass中的对象。所有元素初始值均设为initialElement。

jarray NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement);

参数:
env:JNI接口指针。
length:数组大小。
elementClass:数组元素类。
initialElement:初始值。

返回值:
Java数组对象。如果无法构造数组,则为NULL

抛出:
OutOfMemoryError:如果系统内存不足

GetObjectArrayElement( ) 返回Object数组的元素。

jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index);

参数:
env:JNI接口指针。
array:Java数组。
index:数组下标。

返回值:
Java对象

抛出:
ArrayIndexOutOfBoundsException:如果index不是数组中的有效下标

SetObjectArrayElement( ) 设置Object数组的元素。

void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value);

参数:
env:JNI接口指针。
array:Java数组。
index:数组下标。
value:新值。

抛出:
ArrayIndexOutOfBoundsException:如果index不是数组中的有效下标
ArrayStoreException:如果value的类不是数组元素类的子类

New[PrimitiveType]Array( )例程

ArrayType NewArray(JNIEnv *env, jsize length);

用于构造新基本类型数组对象的一系列操作。

参数:
env:JNI接口指针。
length:数组长度。

返回值:
Java数组。如果无法构造该数组,则为NULL

下表说明了特定的基本类型数组构造函数。用户应把New[PrimitiveType]Array替换为

New[PrimitiveType]Array例程 数组类型
NewBooleanArray( ) jbooleanArray
NewByteArray( ) jbyteArray
NewCharArray( ) jcharArray
NewShortArray( ) jshortArray
NewIntArray( ) jintArray
NewLongArray( ) jlongArray
NewFloatArray( ) jfloatArray
NewDoubleArray( ) jdoubleArray

Get[PrimitiveType]ArrayElements( )例程

jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index);

参数:
env:JNI接口指针。
array:Java数组。
index:数组下标。

返回值:
Java对象

抛出:
ArrayIndexOutOfBoundsException:如果index不是数组中的有效下标

SetObjectArrayElement( ) 设置Object数组的元素。

void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value);

参数:
env:JNI接口指针。
array:Java数组。
index:数组下标。
value:新值。

抛出:
ArrayIndexOutOfBoundsException:如果index不是数组中的有效下标
ArrayStoreException:如果value的类不是数组元素类的子类

New[PrimitiveType]Array( )例程

ArrayType NewArray(JNIEnv *env, jsize length);

用于构造新基本类型数组对象的一系列操作。

参数:
env:JNI接口指针。
length:数组长度。

返回值:
Java数组。如果无法构造该数组,则为NULL

下表说明了特定的基本类型数组构造函数。用户应把New[PrimitiveType]Array替换为某个实际的基本类型数组构造函数例程名(见下表),然后将ArrayType替换为该例程相应的数组类型。
|New[PrimitiveType]Array例程 |数组类型

NewBooleanArray( ) jbooleanArray
NewByteArray( ) jbyteArray
NewCharArray( ) jcharArray
NewShortArray( ) jshortArray
NewIntArray( ) jintArray
NewLongArray( ) jlongArray
NewFloatArray( ) jfloatArray
NewDoubleArray( ) jdoubleArray

Get[PrimitiveType]ArrayElements( )例程

NativeType *GetArrayElements(JNIEnv *env, ArrayType array, jboolean *isCopy);

一组返回基本类型数组体的函数。
结果在调用相应的Release[PrimitiveType]ArrayElements( )函数前将一直有效。由于返回的数组可能是Java数组的副本,因此对返回数组的更改不必在基本类型数组中反映出来,直到调用了Release[PrimitiveType]ArrayElements()。
如果isCopy不是NULL,*isCopy在复制完成后即被设为JNI_TRUE。如果未复制,则设为JNI_FALSE。

参数:
env:JNI接口指针。
array:Java字符串对象。
isCopy:指向布尔值的指针。

返回值:
返回指向数组元素的指针,如果操作失败,则为NULL

下表说明了特定的基本类型数组元素访问器。应进行下列替换;

将Get[PrimitiveType]ArrayElements替换为表中某个实际的基本类型元素访问器例程名。
将ArrayType替换为对应的数组类型。
将NativeType替换为该例程对应的本地类型。
不管布尔数组在Java虚拟机中如何表示,GetBooleanArrayElements( )将始终返回一个jbooleans类型的指针,其中每一字节代表一个元素(开包表示)。内存中将确保所有其它类型的数组为连续的。

Get[PrimitiveType]ArrayElements例程 数组类型 本地类型
GetBooleanArrayElements( ) jbooleanArray jboolean
GetByteArrayElements( ) jbyteArray jbyte
GetCharArrayElements( ) jcharArray jchar
GetShortArrayElements( ) jshortArray jshort
GetIntArrayElements( ) jintArray jint
GetLongArrayElements( ) jlongArray jlong
GetFloatArrayElements( ) jfloatArray jfloat
GetDoubleArrayElements( ) jdoubleArray jdouble

Release[PrimitiveType]ArrayElements( )例程

void ReleaseArrayElements(JNIEnv *env, ArrayType array, NativeType *elems, jint mode);

通知虚拟机平台相关代码无需再访问elems的一组函数。
elems参数是一个通过使用对应的Get[PrimitiveType]ArrayElements()函数由array导出的指针。必要时,该函数将把对elems的修改复制回基本类型数组。mode参数将提供有关如何释放数组缓冲区的信息。如果elems不是array中数组元素的副本,mode将无效。否则,mode将具有下表所述的功能:

基本类型数组释放模 动作
0 复制回内容并释放elems缓冲区
JNI_COMMIT 复制回内容但不释放elems缓冲区
JNI_ABORT 释放缓冲区但不复制回变化

多数情况下,编程人员将把“0”传给mode参数以确保固定的数组和复制的数组保持一致。其它选项可以使编程人员进一步控制内存管理,但使用时务必慎重。

参数:
env:JNI接口指针。
array:Java数组对象。
elems:指向数组元素的指针。
mode:释放模式。

下表说明了构成基本类型数组撤消程序系列的特定例程。应进行如下替换;

  1. 将Release[PrimitiveType]ArrayElements 替换为下表中的某个实际基本类型数组撤消程序例程名。
  2. 将ArrayType替换为对应的数组类型。
  3. 将NativeType替换为该例程对应的本地类型。
ReleaseArrayElements例程 数组类型 本地类型
ReleaseBooleanArrayElements( ) jbooleanArray jboolean
ReleaseByteArrayElements( ) jbyteArray jbyte
ReleaseCharArrayElements( ) jcharArray jchar
ReleaseShortArrayElements( ) jshortArray jshort
ReleaseIntArrayElements( ) jintArray jint
ReleaseLongArrayElements( ) jlongArray jlong
ReleaseFloatArrayElements( ) jfloatArray jfloat
ReleaseDoubleArrayElements( ) jdoubleArray jdouble

Get[PrimitiveType]ArrayRegion例程

void GetArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize len, NativeType *buf);

将基本类型数组某一区域复制到缓冲区中的一组函数。

参数:
env:JNI接口指针。
array:Java指针。
start:起始下标。
len:要复制的元素数。
buf:目的缓冲区。

抛出:
ArrayIndexOutOfBoundsException:如果区域中的某个下标无效

下表说明了特定的基本类型数组元素访问器。应进行如下替换:

  1. 将Get[PrimitiveType]ArrayRegion替换为表中的某个实际基本类型元素访问器例程名。
  2. 将 ArrayType 替换为对应的数组类型。
  3. 将 NativeType 替换为该例程对应的本地类型。
Get[PrimitiveType]ArrayRegion例程 数组类型 本地类型
GetBooleanArrayRegion( ) jbooleanArray jboolean
GetByteArrayRegion( ) jbyteArray jbyte
GetCharArrayRegion( ) jcharArray jchar
GetShortArrayRegion( ) jshortArray jshort
GetIntArrayRegion( ) jintArray jint
GetLongArrayRegion( ) jlongArray jlong
GetFloatArrayRegion( ) jfloatArray jfloat
GetDoubleArrayRegion( ) jdoubleArray jdouble

Set[PrimitiveType]ArrayRegion例程

void SetArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize len, NativeType *buf);

将基本类型数组的某一区域从缓冲区中复制回来的一组函数。

参数:
env:JNI接口指针。
array: Java数组。
start:起始下标。
len:要复制的元素数。
buf:源缓冲区。

抛出:
ArrayIndexOutOfBoundsException:如果区域中的某个下标无效

下表说明了特定的基本类型数组元素访问器。应进行如下替换:

  1. 将Set[PrimitiveType]ArrayRegion替换为表中的实际基本类型元素访问器例程名。
  2. 将ArrayType替换为对应的数组类型。
  3. 将NativeType替换为该例程对应的本地类型。
Set[PrimitiveType]ArrayRegion例程 数组类型 本地类型
SetBooleanArrayRegion( ) jbooleanArray jboolean
SetByteArrayRegion( ) jbyteArray jbyte
SetCharArrayRegion( ) jcharArray jchar
SetShortArrayRegion( ) jshortArray jshort
SetIntArrayRegion( ) jintArray jint
SetLongArrayRegion( ) jlongArray jlong
SetFloatArrayRegion( ) jfloatArray jfloat
SetDoubleArrayRegion( ) jdoubleArray jdouble

注册本地方法

RegisterNatives( )

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

向clazz参数指定的类注册本地方法。methods参数将指定JNINativeMethod结构的数组,其中包含本地方法的名称、签名和函数指针。nMethods参数将指定数组中的本地方法数。

参数:
env:JNI接口指针。
clazz:Java类对象。
methods:类中的本地方法。
nMethods:类中的本地方法数。

返回值:
成功时返回 “0”;失败时返回负数

抛出:
NoSuchMethodError:如果找不到指定的方法或方法不是本地方法

JNINativeMethod 结构定义如下所示:

typedef struct {
    char *name;
    char *signature;
    void *fnPtr;
} JNINativeMethod;

函数指针通常必须有下列签名:

ReturnType (*fnPtr)(JNIEnv *env, jobject objectOrClass, ...);

UnregisterNatives( )

jint UnregisterNatives(JNIEnv *env, jclass clazz);

取消注册类的本地方法。类将返回到链接或注册了本地方法函数前的状态。该函数不应在常规平台相关代码中使用。相反,它可以为某些程序提供一种重新加载和重新链接本地库的途径。

参数:
env:JNI接口指针。
clazz:Java类对象。

返回值:
成功时返回“0”;失败时返回负数

监视程序操作

MonitorEnter( )

jint MonitorEnter(JNIEnv *env, jobject obj);

进入与obj所引用的基本Java对象相关联的监视程序。每个Java对象都有一个相关联的监视程序。如果当前线程已经拥有与obj相关联的监视程序,它将使指示该线程进入监视程序次数的监视程序计数器增 1。如果与 obj 相关联的监视程序并非由某个线程所拥有,则当前线程将变为该监视程序的所有者,同时将该监视程序的计数器设置为 1。如果另一个线程已拥有与 obj 关联的监视程序,则在监视程序被释放前当前线程将处于等待状态。监视程序被释放后,当前线程将尝试重新获得所有权。

参数:
env:JNI接口指针。
obj:常规Java对象或类对象。

返回值:
成功时返回“0”;失败时返回负数

MonitorExit( )

jint MonitorExit(JNIEnv *env, jobject obj);

当前线程必须是与obj所引用的基本Java对象相关联的监视程序的所有者。线程将使指示进入监视程序次数的计数器减 1。如果计数器的值变为 0,当前线程释放监视程序。

参数:
env:JNI接口指针。
obj:常规Java对象或类对象。

返回值:
成功时返回“0”;失败时返回负数

Java虚拟机接口

GetJavaVM( )

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

返回与当前线程相关联的Java虚拟机接口(用于调用API中)。结果将放在第二个参数vm所指向的位置。

参数:
env:JNI接口指针。
vm:指向放置结果的位置的指针。

返回值:
成功时返回“0”;失败时返回负数

调用API

调用API允许软件厂商将Java虚拟机加载到任意的本地程序中。厂商可以交付支持Java的应用程序,而不必链接Java虚拟机源代码。本章首先概述了调用API。然后是所有调用API函数的引用页。若要增强Java虚拟机的嵌入性,可以用几种方式来扩展JDK 1.1.2中的调用API。

概述

以下代码示例说明了如何使用调用API中的函数。在本例中,C++代码创建Java虚拟机并且调用名为Main.test的静态方法。为清楚起见,我们略去了错误检查。

#include <jni.h>
/* 其中定义了所有的事项 */
JavaVM *jvm;
/* 表示 Java 虚拟机*/
JNIEnv *env;
/* 指向本地方法接口的指针 */
JDK1_1InitArgs vm_args; /* JDK 1.1 虚拟机初始化参数 */
vm_args.version = 0x00010001; /* 1.1.2 中新增的:虚拟机版本 */
/* 获得缺省的初始化参数并且设置类路径 */
JNI_GetDefaultJavaVMInitArgs(&vm_args);
vm_args.classpath = ...;
/* 加载并初始化 Java 虚拟机,返回env中的JNI 接口指针 */
JNI_CreateJavaVM(&jvm, &env, &vm_args);
/* 用 JNI 调用 Main.test 方法 */
jclass cls = env->FindClass("Main");
jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
env->CallStaticVoidMethod(cls, mid, 100);
/* 结束。*/
jvm->DestroyJavaVM();

本例使用了API中的三个函数。调用API允许本地应用程序用JNI接口指针来访问虚拟机特性。其设计类似于Netscape的JRI嵌入式接口。

创建虚拟机

JNI_CreateJavaVM()函数加载并初始化Java虚拟机,然后将指针返回到JNI接口指针。调用JNI_CreateJavaVM()的线程被看作主线程。

卸载虚拟机

主线程不能自己断开与虚拟机的连接。而是必须调用DestroyJavaVM( )来卸载整个虚拟机。

虚拟机等到主线程成为唯一的用户线程时才真正地卸载。用户线程包括Java线程和附加的本地线程。之所以存在这种限制是因为Java线程或附加的本地线程可能正占用着系统资源,例如锁,窗口等。虚拟机不能自动释放这些资源。卸载虚拟机时,通过将主线程限制为唯一的运行线程,使释放任意线程所占用系统资源的负担落到程序员身上。

初始化结构

不同的Java虚拟机实现可能会需要不同的初始化参数。很难提出适合于所有现有和将来的Java虚拟机的标准初始化结构。作为一种折衷方式,我们保留了第一个域(version)来识别初始化结构的内容。嵌入到JDK 1.1.2中的本地应用程序必须将版本域设置为0x00010001。尽管其它实现可能会忽略某些由JDK所支持的初始化参数,我们仍然鼓励虚拟机实现使用与JDK一样的初始化结构。0x80000000到0xFFFFFFFF之间的版本号需保留,并且不为任何虚拟机实现所识别。

以下代码显示了初始化JDK 1.1.2中的Java虚拟机所用的结构。

typedef struct JavaVMInitArgs {
    /* 前两个域在 JDK 1.1 中保留,并在 JDK 1.1.2 中正式引入。*/
    /* Java 虚拟机版本 */
    jint version;
    /* 系统属性。*/
    char **properties;
    /* 是否检查 Java 源文件与已编译的类文件之间的新旧关系。*/
    jint checkSource;
    /* Java 创建的线程的最大本地堆栈大小。*/
    jint nativeStackSize;
    /* 最大 Java 堆栈大小。*/
    jint javaStackSize;
    /* 初始堆大小。*/
    jint minHeapSize;
    /* 最大堆大小。*/
    jint maxHeapSize;
    /* 控制是否校验 Java 字节码:0 无,1 远程加载的代码,2 所有代码。*/
    jint verifyMode;
    /* 类加载的本地目录路径。*/
    const char *classpath;
    /* 重定向所有虚拟机消息的函数的钩子。*/
    jint (*vfprintf)(FILE *fp, const char *format, va_list args);
    /* 虚拟机退出钩子。*/
    void (*exit)(jint code);
    /* 虚拟机放弃钩子。*/
    void (*abort)();
    /* 是否启用类 GC。*/
    jint enableClassGC;
    /* GC 消息是否出现。*/
    jint enableVerboseGC;
    /* 是否允许异步 GC。*/
    jint disableAsyncGC;
    /* 三个保留的域。*/
    jint reserved0;
    jint reserved1;
    jint reserved2;
} JDK1_1InitArgs;

在JDK 1.1.2中,初始化结构提供了钩子,这样在虚拟机终止时,本地应用程序可以重定向虚拟机消息并获得控制权。当本地线程与JDK 1.1.2中的Java虚拟机连接时,以下结构将作为参数进行传递。实际上,本地线程与JDK 1.1.2连接时不需要任何参数。JDK1_1AttachArgs 结构仅由C编译器的填充槽组成,而C编译器不允许空结构。

typedef struct JDK1_1AttachArgs {
    /*
    * JDK 1.1 不需要任何参数来附加本地线程。此处填充的作用是为了满足不允许空结构的C编译器的要求。
    */
    void *__padding;
} JDK1_1AttachArgs;

调用API函数

JavaVM类型是指向调用API函数表的指针。以下代码示例显示了这种函数表。

typedef const struct JNIInvokeInterface *JavaVM;

const struct JNIInvokeInterface ... = {
NULL,
NULL,
NULL,
DestroyJavaVM,
AttachCurrentThread,
DetachCurrentThread,
};

注意,JNI_GetDefaultJavaVMInitArgs( )、JNI_GetCreatedJavaVMs( )和JNI_CreateJavaVM( ) 这三个调用API函数不是JavaVM函数表的一部分。不必先有JavaVM结构,就可以使用这些函数。

JNI_GetDefaultJavaVMInitArgs( )

jint JNI_GetDefaultJavaVMInitArgs(void *vm_args);

返回Java虚拟机的缺省配置。在调用该函数之前,平台相关代码必须将vm_args->version 域设置为它所期望虚拟机支持的JNI版本。在JDK 1.1.2中,必须将vm_args->version设置为0x00010001。(JDK 1.1不要求平台相关代码设置版本域。为了向后兼容性,如果没有设置版本域,则JDK 1.1.2假定所请求的版本为0x00010001。JDK的未来版本将要求把版本域设置为适当的值。)该函数返回后,将把vm_args->version设置为虚拟机支持的实际JNI版本。

参数:
vm_args:指向VM-specific initialization(特定于虚拟机的初始化)结构的指针,缺省参数填入该结构。

返回值:
如果所请求的版本得到支持,则返回“0”;如果所请求的版本未得到支持,则返回负数

JNI_GetCreatedJavaVMs( )

jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs);

返回所有已创建的Java虚拟机。将指向虚拟机的指针依据其创建顺序写入vmBuf缓冲区。最多写入bufLen项。在*nVMs中返回所创建虚拟机的总数。JDK 1.1不支持在单个进程中创建多个虚拟机。

参数:
vmBuf:指向将放置虚拟机结构的缓冲区的指针。
bufLen:缓冲区的长度。
nVMs:指向整数的指针。

返回值:
成功时返回“0”;失败则返回负数

JNI_CreateJavaVM( )

jint JNI_CreateJavaVM(JavaVM **p_vm, JNIEnv **p_env, void *vm_args);

加载并初始化Java虚拟机。当前线程成为主线程。将env参数设置为主线程的JNI接口指针。JDK 1.1.2不支持在单个进程中创建多个虚拟机。必须将vm_args中的版本域设置为0x00010001。

参数:
p_vm:指向位置(其中放置所得到的虚拟机结构)的指针。
p_env:指向位置(其中放置主线程的 JNI 接口指针)的指针。
vm_args: Java 虚拟机初始化参数。

返回值:
成功时返回“0”;失败则返回负数

DestroyJavaVM( )

jint DestroyJavaVM(JavaVM *vm);

卸载Java虚拟机并回收资源。只有主线程能够卸载虚拟机。调用DestroyJavaVM( ) 时,主线程必须是唯一的剩余用户线程。

参数:
vm:将销毁的Java虚拟机。

返回值:
成功时返回“0”;失败则返回负数

JDK 1.1.2 不支持卸载虚拟机。

AttachCurrentThread( )

jint AttachCurrentThread(JavaVM *vm, JNIEnv **p_env, void *thr_args);

将当前线程连接到Java虚拟机。在JNIEnv参数中返回JNI接口指针。试图连接已经连接的线程将不执行任何操作。本地线程不能同时连接到两个Java虚拟机上。

参数:
vm:当前线程所要连接到的虚拟机。
p_env:指向位置(其中放置当前线程的 JNI 接口指针)的指针。
thr_args:特定于虚拟机的线程连接参数。

返回值:
成功时返回“0”;失败则返回负数

DetachCurrentThread( )

jint DetachCurrentThread(JavaVM *vm);

断开当前线程与Java虚拟机之间的连接。释放该线程占用的所有Java监视程序。通知所有等待该线程终止的Java线程。主线程(即创建Java虚拟机的线程)不能断开与虚拟机之间的连接。作为替代,主线程必须调用JNI_DestroyJavaVM( )来卸载整个虚拟机。

参数:
vm:当前线程将断开连接的虚拟机。

返回值:
成功时返回“0”;失败则返回负数

CreateFile( )

函数原型

HANDLE CreateFile(
        LPCTSTR lpfileName,
        DWORD deDesiredAccess,
        DWORD dwShareMode,
        LPSECURITY_ATTRIBUTES lpSecurityAttributes
        DWORD dwCreationDesposition,
        DWORD dwFlagsAndAtrributes,
        HANDLE hTemplateFile
);
  1. 函数说明
    该函数创建、打开或截断一个文件,并返回一个能够被用来存取该文件的句柄。此句柄允许读书据、写数据以及移动文件的指针。CreateFile函数既可以做为一个宽自负函数使用,也可以作为一个ANSI函数来用。

  2. 参数说明
    lpFileName:指向文件字符串的指针。
    dwDesireAccess:制定文件的存取模式,可以取下列值:

    1. 0:制定可以查询对象。
    2. GENERIC_READ:指定可以从文件中度去数据。
    3. GENERIC_WRITE:指定可以向文件中写数据。

    dwShareMode:指定文件的共享模式,可以取下列值:

    1. 0:不共享。
    2. FILE_SHARE_DELETE:在 Windows NT 系统中,只有为了删除文件而进行的打开操作才会成功。
    3. FILE_SHARE_READ:只有为了从文件中度去数据而进行的打开操作才会成功。
    4. FILE_SHARE_WRITE:只有为了向文件中写数据而进行的打开操作才会成功。

    lpSecurityAttributes :指定文件的安全属性。
    dwCreationDisopsition:指定创建文件的方式,可以取以下值:

    1. CREATE_NEW:创建新文件,如果文件已存在,则函数失败。
    2. CREATE_ALWAYS:创建爱内心文件,如果文件已存在,则函数将覆盖并清除旧文件。
    3. OPEN_EXISTING:打开文件,如果文件不存在,函数将失败。
    4. OPEN_ALWAYS:打开文件,如果文件不存在,则函数将创建一个新文件。
    5. TRUNCATE_EXISTING:打开外呢间,如果文件存在,函数将文件的大小设为零,如果文件不存在,函数将失败返回。

    dwFlagsAndAtrributes :指定新建文件的属性和标志,它可以取以下值:

    1. FILE_ATTRIBUTE_ARCHIVE:归档属性。
    2. FILE_ATTRIBUTE_HIDDEN:隐藏属性。
    3. FILE_ATTRIBUTE_NORMAL:正常属性。
    4. FILE_ATTRIBUTE_READONLY:只读属性。
    5. FILE_ATTRIBUTE_READONLY:只读属性。
    6. FILE_ATTRIBUTE_TEMPORARY:临时存储文件,系统总是将临时文件的所有数据读入内存中,以加速对该文件的访问速度。用户应该尽快删除不再使用的临时文件。
    7. FILE_FLAG_OVERLAPPED:用户可以通过一个 OVERLAPPED 结构变量来保存和设置文件读写指针,从而可以完成重叠式的读和写。一般用于数量比较大的读些操作。

    hTemplateFile :指向一个具有GENERIC_READ属性的文件的句柄,该文件为要创建的文件提供文件属性和文件扩展属性。

  3. 注意事项
    函数成功将返回指定文件的句柄,否则返回NULL

总结

至此整个JNI完全手册引用结束。日后开发过程中该手册相当于一本字典,可以用来查阅。
本文内容主要参考http://blog.csdn.net/yanbober/article/details/45310365,感谢博主的辛劳……

你可能感兴趣的:(Android,Studio,Android,jni)