reverse_xiaoyu

忘记并不可怕,可怕的是你从来就都不知道!

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

JNI 函数(三)对象操作

(一)、直接创建一个 Java 对象

函数原型:jobject AllocObject(JNIEnv *env, jclass clazz);

  不借助任何构造函数的情况下分配一个新的 Java 对象,返回对象的一个引用。

  参数:

    env:JNI 接口指针

    clazz::Java 类对象

  返回:

    返回一个 Java 对象,如果该对象无法被创建,则返回 NULL。

  异常:

    如果该类是接口或者是抽象类,则抛出 InstantiationException

    如果是内存溢出,则抛出 OutOfMemoryError

(二)、根据某个构造函数来创建 Java 对象

函数原型:jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...);

函数原型:jobject NewObjectA(JNIEnv *env, jclass clazz,jmethodID methodID, const jvalue *args);

函数原型:jobject NewObjectV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

  构造一个新的 Java 对象,methodID 表明需要调用一个构造函数。这个 ID 必须通过调用 GetMethodID() 获得,GetMethodID() 为函数名,void(V) 为返回值。clazz 参数不能指定一个数组类

    NewObject:需要把所有构造函数的入参,放在参数 methodID 之后。NewObject() 接受这些参数并将它们传递给需要被调用的 Java 的构造函数

    NewObjectA:在methodID 后面,放了一个类型为 jvalue 的参数数组——args,该数组存放着所有需要传递给构造函数的参数。NewObjectA() 接收到这个数组中的所有参数,并且按照顺序将它们传递给需要调用的 Java 方法。

    NewObjectV:在methodID 后面,放了一个类型为 va_lis t的 args,参数存放着所有需要传递给构造函数的参数。NewObjectv() 接收到所有的参数,并且按照顺序将它们传递给需要调用的 Java 方法。

  参数:

    env:JNI 接口指针

    clazz::Java 类

    methodID:构造函数的方法 ID

  附加参数:

    NewObject 的附加参数:arguments 是构造函数的参数

    NewObjectA 的附加参数:args 是构造函数的参数数组

    NewObjectV 的附加参数:args 是构造函数的参数 list

  返回:

    Java 对象,如果无法创建该对象,则返回 NULL

  异常:

    如果传入的类是接口或者抽象类,则抛出 InstantiationException

    如果内存溢出,则抛出 OutOfMemoryError

  所有的异常都是通过构造函数抛出

(三)、获取某个对象的“类”

函数原型:jclass GetObjectClass(JNIEnv *env, object obj);

  返回 obj 对应的类

  参数:

    env:JNI 接口指针

    obj:Java 对象,不能为 NULL

  返回:

    返回一 个Java “类” 对象

(四)、获取某个对象的“类型”

函数原型:jobjectRefType GetObjectRefType(JNIEnv *env, jobject obj);

  返回 obj 参数所以指向对象的类型,参数 obj 可以是局部变量,全局变量或者若全局引用。

  参数:

    env:JNI 接口指针

    obj:局部、全局或弱全局引用

  返回:

    JNIInvalidRefType=0:代表 obj 参数不是有效的引用类型

    JNILocalRefType=1:代表 obj 参数是局部变量类型

    JNIGlobalRefType=2:代表 obj 参数是全局变量类型

    JNIWeakGlobalRefType=3:代表 obj 参数是弱全局有效引用

  无效的引用就是没有引用的引用。也就是说,obj 的指针没有指向内存中创建函数时候的地址,或者已经从 JNI 函数中返回了。所以说 NULL 就是无效的引用。并且 GetObjectRefType(env, NULL) 将返回类型是 JNIInvalidRefType。但是空引用返回的不是 JNIInvalidRefType,而是它被创建时候的引用类型。

  PS:不能在引用在删除的时候,调用该函数

(五)、判断某个对象是否是某个“类”的子类

函数原型:jboolean IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz);

  测试 obj 是否是 clazz 的一个实例

  参数:

    env:JNI 接口指针

    obj:一个 Java 对象

    clazz:一个 Java 的类

  返回:

    如果 obj 是 clazz 的实例,则返回 JNI_TRUE;否则则返回 JNI_FALSE;一个空对象可以是任何类的实例。

(六)、判断两个引用是否指向同一个引用

函数原型:jboolean IsSampleObject(JNIEnv *env, jobject ref1, jobject ref2);

  判断两个引用是否指向同一个对象

  参数:

    env:JNI 接口指针

    ref1:Java 对象

    ref2:Java 对象

  返回:

    如果同一个类对象,返回 JNI_TRUE;否则,返回 JNI_FALSE;

(七)、返回属性id

函数原型:jfieldID GetFieldID(JNIEnv *env,jclass clazz,const char *name,const char *sig);

  获取某个类的非静态属性 id。通过方法属性名以及属性的签名(也就是属性的类型),来确定对应的是哪个属性。通过检索这个属性 ID,我们就可以调用 Get <type>Field 和 Set <type>Field了,就是我们常用的 getset 方法

  参数:

    env:JNI 接口指针

    clazz:一个 Java 类对象

    name:以 "0" 结尾的,而且字符类型是 "utf-8" 的属性名称

    sig:以 "0" 结尾的,而且字符类型是 "utf-8" 的属性签名

  返回

    属性对应 ID,如果操作失败,则返回 NULL

  异常:

    如果找不到指定的属性,则抛出 NoSuchFieldError

    如果类初始化失败,则抛出 ExceptionInitializerError

    如果内存不足了,则抛出 OutOfMemoryError

  PS:GetFieldID() 可能会导致还未初始化的类开始初始化,同时在获取数组的长度不能使用 GetFieldID(),而应该使用 GetArrayLength()

(八)、返回属性id系列

通用函数类型:NativeType Get[type]Field(JNIEnv *env, jobject obj, jfieldID fieldID);

  返回某个类的非静态属性的值,这是一组函数的简称,具体如下:

  1. jobject     GetObjectField    (JNIEnv *env, jobject obj, jfieldID fielD)
  2. jboolean  GetBooleanField (JNIEnv *env, jobject obj, jfieldID fielD)
  3. jbyte       GetByteField        (JNIEnv *env, jobject obj, jfieldID fielD)
  4. jchar       GetCharField       (JNIEnv *env, jobject obj, jfieldID fielD)
  5. jshort      GetShortField      (JNIEnv *env, jobject obj, jfieldID fielD)
  6. jint          GetIntField           (JNIEnv *env, jobject obj, jfieldID fielD)
  7. jlong       GetLongField       (JNIEnv *env, jobject obj, jfieldID fielD)
  8. jfloat       GetFloatField       (JNIEnv *env, jobject obj, jfieldID fielD)
  9. jdouble   GetDoubleField   (JNIEnv *env, jobject obj, jfieldID fielD)

  参数:

    env:JNI 接口指针

    obj:Java 对象,不能为空

    fieldID:有效的 fieldID

  返回:

    对应属性的值

(九)、设置属性id系列

通用函数类型:void Set<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID, NativeType value)

  设置某个类的的非静态属性的值。其中具体哪个属性通过 GetFieldID() 来确定哪个属性。这是一组函数的简称,具体如下:

  1. void SetObjectField     (jobject)
  2. void SetBooleanField  (jboolean)
  3. void SetByteField        (jbyte)
  4. void SetCharField       (jchar)
  5. void SetShortField      (jshort)
  6. void SetIntField           (jint)
  7. void SetLongField       (jlong)
  8. void SetFloatField       (jfloat)
  9. void SetDoubleField    (jdouble)

  参数:

    env:JNI 接口指针

    obj:Java 对象,不能为空

    fieldID:有效的属性 ID

    value:属性的新值

  返回值:

    void

(十)、获取某个类的某个方法id

函数原型:jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char*name, const char* sig);

  返回某个类或者接口的方法 ID,该方法可以是被定义在 clazz 的父类中,然后被 clazz 继承。我们是根据方法的名字以及签名来确定一个方法的。

  PS:GetMethodID()会造成还未初始化的类,进行初始化

  如果想获取构造函数的 ID,请提供 init 作为方法名称,并将 void(V) 作为返回类型

  参数:

    env:JNI 接口指针

    clazz:Java 类对象

    name:以 0 结尾的,并且是 "utf-8" 的字符串的方法名称

    sig:以 0 结尾的,并且是 "utf-8" 的字符串的方法签名

  返回:

    返回一个方法 ID,没有找到指定的方法,则返回 NULL

  异常:

    如果找不到指定的方法,则抛出 NoSuchMethodError

    如果累初始化失败,则抛出 ExceptionInInitializerError

    如果内存不够,则抛出 OutOfMemoryError

(十一)、调用Java实例的某个非静态方法“系列”

通用函数类型:NativeType Call<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...);

通用函数类型:NativeType Call<type>MethodA(JNIEnv *env, jobjct obj, jmethodID methodID, const jvalue *args);

通用函数类型:NativeType Call<type>MethodV(JNEnv *env, jobject obj, jmethodID methodID, va_list args);

  这一些列都是在 native 中调用 Java 对象的某个非静态方法,它们的不同点在于传参不同。是根据方法 ID 来指定对应的 Java 对象的某个方法。methodID 参数需要调用 GetMethodID() 获取。

  PS:当需要调用某个"private"函数或者构造函数时,这个methodID必须是obj类的方法,不能是它的父类的方法。

  下面我们来看下他们的不同点

    CallMethod:需要把方法的入参放在参数 methodID 后面。CallMethod() 其实把这些参数传递给需要调用的 Java 方法。

    CallMethodA:在 methodID 后面,有一个类型为 jvalue 的 args 数组,该数组存放所有需要传递给构造函数的参数。CallMethodA() 收到这个数组中的参数,是按照顺序将他们传递给对应的 Java 方法。

    CallMethodV:在 methodID 后面,有一个类型 va_list 的参数 args,它存放着所有需要传递给构造函数的参数。CallMethodV() 接收所有的参数,并且按照顺序将它们传递给需要调用的 Java 方法。

Call<type>Method Routine 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

 

  参数:

    env:JNI 接口指针

    obj:对应的 Java 对象

    methodID:某个方法的方法 id

  返回:

    返回调用 Java 方法对应的结果

  异常:

    在 Java 方法执行过程中产生的异常。

(十二)、调用某个类的非抽象方法

  调用父类中的实例方法,如下系列

    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, const jvalue *args);

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

  这一系列操作就是根据特定的类,和其方法 ID 来调用 Java 对象的实例的非静态方法,methodID 参数需要调用 GetMethodID() 获取。

  CallNonvirtual<Type>Method 和 Call<type>Method 是不同的,其中 CallNonvirtual<Type>Method 是基于"类",而和 Call<type>Method 是基于类的对象。所以说 CallNonvirtual<Type>Method 的入参是 clazz,methodID 必须来源于 obi 的类,而不是它的父类

  下面我们来看下他们的不同点

    CallNonvirtual<type>Method :需要把方法的入参放在参数 methodID 后面。CallNonvirtual<type>Method() 其实把这些参数传递给需要调用的Java方法。

    CallNonvirtual<type>Method:在 methodID 后面,有一个类型为 jvalue 的args数组,该数组存放所有需要传递给构造函数的参数。CallNonvirtual<type>Method() 收到这个数组中的参数,是按照顺序将他们传递给对应的 Java 方法

    CallNonvirtual<type>MethodV :在 methodID 后面,有一个类型 va_list 的参数 args,它存放着所有需要传递给构造函数的参数。 CallNonvirtual<type>MethodV() 接收所有的参数,并且按照顺序将它们传递给需要调用的 Java 方法。

  将上面这系列方法展开如下:

  将上面这系列方法展开如下:

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

  参数:

    env:JNI 接口指针

    obj:Java 对象

    clazz:Java 类

    methodID:方法 ID

  返回:

    调用 Java 方法的结果

  抛出异常:

  在 Java 方法中执行过程可能产生的异常

(十三)、获取静态(static)属性

函数原型:jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char* name, const char *sig);

  获取某个类的某个静态属性 ID,根据属性名以及标签来确定是哪个属性。GetStaticField() 和 SetStaticField() 通过使用属性 ID 来对属性进行操作的。如果这个类还没有初始化,直接调用 GetStaticFieldID() 会引起这个类进行初始化。

  参数:

    env:JNI 接口指针

    clazz:Java 类

    name:静态属性的属性名,是一个编码格式 "utf-8" 并且以 0 结尾的字符串。

    sig:属性的签名,是一个编码格式 "utf-8" 并且以 0 结尾的字符串。

  返回:

    返回静态属性 ID,如果指定的静态属性无法找则返回 NULL

  异常:

    如果指定的静态属性无法找到则抛出 NoSuchFieldError

    如果类在初始化失败,则抛出 ExceptionInInitializerError

    如果内存不够,则抛出 OutOfMemoryError

(十四)、获取静态(static)属性系列

函数通用类型:NativeType GetStatic<type>Field(JNIEnv *env, jclass clazz, jfieldID fieldID);

  这个系列返回一个对象的静态属性的值。可以通过 GetStaticFieldID() 来获取静态属性的的 ID,有了这个 ID,我们就可以获取这个对其进行操作了

  下面表明了函数名和函数的返回值,所以只需要替换 GetStatic<type>Field 中的类替换为该字段的Java类型或者表中的实际静态字段存取器。并将 NativeType 替换为相应的本地类型

GetStatic<type>Field Routine Name Native Type
GetStaticObjectField() jobject
GetStaticBooleanField() jboolean
GetStaticByteField() jbyte
GetStaticCharField() jchar
GetStaticShortField() jshort
GetStaticIntField() jint
GetStaticLongField() jlong
GetStaticFloatField() jfloat
GetStaticDoubleField() jdouble

 

  参数:

    env:JNI 接口指针

    clazz:Java 类

    field:静态属性 ID

  返回:

    返回静态属性

(十五)、设置静态属性系列

函数通用原型:void SetStatic<type>Field(JNIEnv *env, jclass clazz, jfieldID fieldID, NativeType value);

  这个系列是设置类的静态属性的值。可以通过 GetStaticFieldID() 来获取静态属性的 ID。

  下面详细介绍了函数名和其值,你可以通过 SetStatic<type> 并传入的 NativeType 来设置 Java 中的静态属性。

 

SetStatic<type>Field Routine Name NativeType
SetStaticObjectField() jobject
SetStaticBooleanField() jboolean
SetStaticByteField() jbyte
SetStaticCharField() jchar
SetStaticShortField() jshort
SetStaticIntField() jint
SetStaticLongField() jlong
SetStaticFloatField() jfloat
SetStaticDoubleField() jdouble

  参数:

    env:JNI 接口指针

    clazz:Java 类

    field:静态属性 ID

    value:设置的值

(十六)、获取静态函数ID

函数原型:jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char sig);

  返回类的静态方法 ID,通过它的方法名以及签名来确定哪个方法。如果这个类还没被初始化,调用 GetStaticMethodID() 将会导致这个类初始化。

  参数:

    env:JNI 接口指针

    clazz:Java 类

    name:静态方法的方法名,以 "utf-8" 编码的,并且以 0 结尾的字符串

    sig:方法签名,以 "utf-8" 编码的,并且以 0 结尾的字符串

  返回:

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

  异常:

    如果没有找到对应的静态方法,则抛出 NoSuchMethodError

    如果类初始化失败,则抛出 ExceptionInInitializerError

    如果系统内存不足,则抛出 OutOfMemoryError

(十七)、调用静态函数系列

函数通用原型: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, jmethodID methodid, va_list args);

  根据指定的方法 ID,就可以操作 Java 对象的静态方法了。可以通过 GetStaticMethodID() 来获得 methodID。方法的 ID 必须是 clazz的,而不是其父类的方法 ID。

  下面就是详细的方法了

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

  参数:

    env:JNI 接口指针
    clazz:Java 类
    methodID:静态方 法ID
  返回:
    返回静态的 Java 方法的调用方法

  异常:
    在 Java 方法中执行中抛出的异常

 

posted on 2020-12-16 21:59  Reverse-xiaoyu  阅读(1682)  评论(0编辑  收藏  举报