美文网首页
3.JNI:取得Java属性和设置Java属性值

3.JNI:取得Java属性和设置Java属性值

作者: BUG弄潮儿 | 来源:发表于2023-04-14 15:31 被阅读0次

    1. 取得Java属性/设定Java属性值

    • 获得了相应属性的jfieldID之后,就可以使用
    Set<TYPE>Field
    Get<TYPE>Field
    SetStatic<TYPE>Field
    GetStatic<TYPT>Field
    

    等函数来对Java属性进行操作了。

    • 类实例方法
    Set/GetBooleanField
    Set/GetByteField
    Set/GetDoubleField
    Set/GetFloatField
    Set/GetIntField
    Set/GetLongField
    Set/GetShortField
    Set/GetObjectField
    
    • 类静态方法
    Set/GetStaticBooleanField
    Set/GetStaticByteField
    Set/GetStaticDoubleField
    Set/GetStaticFloatField
    Set/GetStaticIntField
    Set/GetStaticLongField
    Set/GetStaticShortField
    Set/GetStaticObjectField
    
    • 怎样获取数组的属性呢?

    可以使用GetObjectField来获取数组类型的属性。不过JNI提供了一系列方法获取数组的属性,后续介绍。

    2. 案例

    在C/C++中修改Java中的属性

    package com.omg;
    
    public class TestNative {
    
        public int number;
        
        public native void sayHello();
    
    }
    

    C++代码

    jclass clazz_TestNative = env->GetObjectClass( obj);
    jfieldID id_number = env->GetFieldID(clazz_TestNative, "number", "I");
    jint number = env->GetIntFiled(obj, id_number);
    count << number << endl;
    env->SetIntField(obj, id_number, 100L);
    

    3. Java方法调用

    • JNIEnv提供了众多的 Call<TYPE>Method 与 CallStatic<TYPE>Method,还有CallNonvirtual<TYPE>Method函数。需要通过GetMethodID取得相应方法的jmethodID来传入上述函数的参数中。

    • 调用实例方法的三种形式

    Call<TYPE>Method( jobject obj, jmethodID id, ...);
    Call<TYPE>MethodV( jobject obj, jmethodID id, va_list lst);
    Call<TYPE>MethodA( jobject obj, jmethodID id, jvalue* v);
    

    第一种是最常用的方式

    第二种是当调用这个函数的时候,有一个指向参数表的va_list变量时使用(不常用)

    第三种是当调用这个函数的时候,有一个指向jvalue或者jvalue数组的指针时使用

    调用静态方法的三种形式

    CallStatic<TYPE>Method( jclass clazz, jmethodID id, ...);
    CallStatic<TYPE>MethodV( jclass clazz, jmethodID id, va_list lst);
    CallStatic<TYPE>MethodA( jclass clazz, jmethodID id, jvalue* v);
    

    伪代码

    java:
    
    public boolean function(int i, double d, char c){
        //......
    }
    
    C
    
    env->CallBooleanMethod(obj, id_function, 100L, 1.11, L'3')
    
    jvalue * args = new jvalue[3];
    args[0].i = 100L;
    args[1].d = 3.44;
    args[2].c = L'3';
    env->CallBooleanMethod( obj, id_function, args);
    delete [] args;
    

    4. 案例

    在C/C++中代用Java中的方法

    Java代码

    package com.omg;
    
    public class TestNative {
    
        public max(double num1, double num2){
            return num1 > num2 ? num1 : num2;
        }
    
    }
    

    C++代码

    jclass clazz_TestNative = env->GetObjectClass( obj );
    jmethodID id_max = env->GetMetodID( clazz_TestNative, obj, "(DD)D");
    jdouble maxVal = env->GetDoubleMethod(obj, id_max, 2.1, 3.14);
    cout << maxVal << endl;
    

    5. CallNonvirtual<TYPE>Method

    有如下Java代码

    public class Father {
    
        public void function(){
            System.out.println("Father function");
        }
    
    }
    
    public class Child extends Father {
    
        public void function(){
            System.out.println("Child function");
        }
    
    }
    

    想想这段Java代码调用的是哪个类的方法?

    Father p = new Child();
    p.function();
    

    如果想调用父类的function是没有办法的

    有如下C++代码

    class Father {
    
        public:
        void function(){
            cout << "Father function" <<endl;
        }
    
    }
    
    class Child : public Father {
    
        public:
        void function(){
            cout << "Child function" <<endl;
        }
    
    }
    

    想想这段代码调用的是哪个类的成员函数?(调用的是父类的函数)

    Father* p = new Child();
    p->function();
    

    C++有虚函数的概念,修改一下父类加一个 virtual

    class Father {
    
        public:
        virtual void function(){
            cout << "Father function" <<endl;
        }
    
    }
    
    class Child : public Father {
    
        public:
        void function(){
            cout << "Child function" <<endl;
        }
    
    }
    

    再想想这段代码调用的是哪个类的成员函数?(调用的是子类的函数)

    Father* p = new Child();
    p->function();
    

    在Java语言中,所有的函数都是虚函数

    • 在JNI中定义了CallNonvirtual<TYPE>Method就能实现子类对象调用父类方法的功能,如果想要调用一个对象的父类的方法,而不是子类的重写(over write)的方法的话,就可以使用CallNonVirtual<TYPE>Method
    • 要使用CallNonVirtual<TYPE>Method,首先要取得父类及要调用的父类的方法的jmethodID。然后传入到这个函数就能通过子类对象调用被重写(over write)的父类的方法

    5. 案例

    package com.omg;
    
    public class Father {
    
        public void function() {
            System.out.println("Father function");
        }
    
    }
    
    
    package com.omg;
    
    public class Child extends Father {
    
        public void function() {
            System.out.println("Child function");
        }
    
    }
    

    测试

    Java定义成员变量

    public Father p = new Child();
    

    C++代码

    jclass clazz_TestNative = env->GetObjectClass( obj );
    jfieldID id_p = env->GetFieldID(clazz_TestNative, "p", "Lcom/omg/Father;");
    jobject p = env->GetObjectField(obj, id_p);
    
    jclass clazz_Father = env->FindClass( "Lcom/omg/Father;" );
    jmethodID id_Father_function = env->GetMethodID(clazz_Father, "function", "()V");
    
    env->CallVoidMethod(p, id_Father_function);
    
    env->CallNonvirtualVoidMethod(p, clazz_Father, id_Father_function);
    

    相关文章

      网友评论

          本文标题:3.JNI:取得Java属性和设置Java属性值

          本文链接:https://www.haomeiwen.com/subject/phhtjdtx.html