• JNI 函数(三)对象操作


    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 方法中执行中抛出的异常

  • 相关阅读:
    mysql的安全漏洞的一种现象,就是利用转义字符把 ' ' 化没了,然后true 起作用啦
    maven项目中添加MySql依赖失败(以及maven的安装到maven项目的使用过程)
    mysql中的update(更新)与alter(更改)以及 change和modify的区别
    多线程:(充分利用定义任务后,开启多线程实现任务的理解)题目:模拟三个老师同时给50个小朋友发苹果,每个老师相当于一个线程。
    swing更改组件(删除后添加)得到心得:起码得刷新一下啊,可能还得再考虑重绘
    IE设置主页一直无果,尝试了右键软件看目标路径后缀无效,注册表也无效,最后在电脑管家里的工具浏览器保护搞定
    封装的localstorge的插件,store.js
    jquery.cookie用法详细解析,封装的操作cookie的库有jquery.cookie.js
    localstroge可以在页面间传递数值;
    移动开发阻止默认事件,1默认长按复制2拖动时页面默认移动
  • 原文地址:https://www.cnblogs.com/Reverse-xiaoyu/p/14130594.html
Copyright © 2020-2023  润新知