三、C++操作java属性和方法

在第二讲中讲到了C++中操作java程序的方法以及操作步骤,下面就通过实例的方式来体会到底怎么通过JNI提供的方法来

获取、操作 java属性、方法以及父类方法

1、取得/设定Java属性值

在原来java 类TestNative的基础上编写如下代码:

package com.fomagic;
public class TestNative {
    
    public native void sayHello(); //C++本地代码实现    
    public int number=10;  //定义变量初始值为10,在C++中进行修改
        
    public static void main(String[] args) {
        System.loadLibrary("NativeCode");//加载动态链接库,不能加 .dll         
        TestNative test=new TestNative();    //创建本类实例
        test.sayHello();
        
        System.out.println("C++中操作之后的结果:  "+test.number);
    }
 
}


C++中原有代码添加如下:

JNIEXPORT void JNICALL Java_com_fomagic_TestNative_sayHello (JNIEnv *env, jobject obj)
{
    cout<<"Hello World !"<<endl;
    
    jclass clazz_TestNative=env->GetObjectClass(obj);   //通过传入的obj类的对象获取当前类
    jfieldID id_number=env->GetFieldID(clazz_TestNative,"number","I");  //类实例,属性名,(sign)数据类型
    jint number =env->GetIntField(obj,id_number); //  通过 ID 获取当前变量
 
    cout<<"原数据: "<<number <<endl;
 
    env->SetIntField(obj,id_number,100L);  //类实例,变量ID, 修改的java属性值
}


       注:修改的属性值 100L,可以参看第二讲的 “Java类型在C/C++中的映射关系” 图表 (java中 int 对应 C++中 long)

2、调用Java类的方法

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

Call<TYPE>Method(jobject obj ,jmethodID id ,….);

Call<TYPE>MethodV(jobject obj ,jmethodID id ,va_list lst);

Call<TYPE>Method(jobject obj ,jmethodID id ,jvalue* v) ;

 

第一个比较常用

第二个是当调用这个函数有一个指向参数表的va_list变量时使用(只知道是可变参数列表)

第三个当调用函数时有一个指向jvalue或jvalue数组的指针时使用(即传入的是所有参数的变量数组指针)

下面就以第一种方式写下返回较大值的实例:

 

package com.fomagic;
 
public class TestNative {
    
    public native void sayHello(); //C++本地代码实现
    public static void main(String[] args) {
        System.loadLibrary("NativeCode");//加载动态链接库,不能加 .dll         
        TestNative test=new TestNative();    
        test.sayHello();
    }
    double max(double num1,double num2){
        
        return num1>num2 ? num1 : num2;
    }
    
}


 

JNIEXPORT void JNICALL Java_com_fomagic_TestNative_sayHello (JNIEnv *env, jobject obj)
{    
    jclass clazz_TestNative=env->GetObjectClass(obj);  //获取当前类
    jmethodID id_max=env->GetMethodID(clazz_TestNative,"max","(DD)D"); //获取方法ID(签名)
    jdouble maxValue = env->CallDoubleMethod(obj,id_max,100.5,203.1); //调用max方法进行传值
 
    cout<<"较大值: "<<maxValue <<endl; }

 

3、调用Java类父类方法

我们都知道在java中父类创建子类对象只能调用子类的覆盖方法,而C++中子类对象默认调用的父类的方法,当父类方法用虚拟函数关键字virtual修饰时,调用子类覆盖方法

java

C++

Father p=new Child();p.function();           //调用子类覆盖方法Father* p=new Child();p->function();      //默认调用父类方法,用virtual修饰符修饰则调用子类覆盖方法

通过JNI的 CallNonvirtual<TYPE>Method 可以实现子类对象调用父类被覆盖的方法的功能,步骤:

  •       取得父类和需要调用的父类中方法的jmethodID
  •        将jmethodID传入 CallNonvirtual<TYPE>Method

代码:新建Father类 、Child类

package com.fomagic;
 
public class TestNative {
 
    public native void sayHello(); // C++本地代码实现
    public Father p=new Child();  //创建Child 的实例对象
    
    public static void main(String[] args) {
        System.loadLibrary("NativeCode");// 加载动态链接库,不能加 .dll
        TestNative test = new TestNative();
        test.sayHello();
    }
}
 
class Father {
    public void function() {
        System.out.println("Father function");
    }
}
 
class Child extends Father {
    public void function() {
        System.out.println("Child function");
    }
}


C++代码:

JNIEXPORT void JNICALL Java_com_fomagic_TestNative_sayHello (JNIEnv *env, jobject obj)
{
 
    jclass clazz_TestNative=env->GetObjectClass(obj);    
    jfieldID id_p=env->GetFieldID(clazz_TestNative,"p","Lcom/fomagic/Father;");
    jobject p= env->GetObjectField(obj,id_p);
 
    jclass clazz_Father = env->FindClass("com/fomagic/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);
}

 

.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值