jni操作java属性和方法

              之前实现了简单的jni入门实例, 这篇博客将主要介绍使用jni在c++调用java的属性和方法。

 

本地方法函数有两个参数,JNIEnv *和jobject,这两个参数非常重要



 

1.JNI数据类型

为了方便记忆和书写java数据类型与c++数据类型的对应,jni对数据进行封装。具体为下



 

2.获取java属性和方法

 

   首先需要获取对应的java的类,jni专门定义了jclass类型来表示java的Class类,JNIEvn类中有几个函数取得jclass:

      1.jclass FindClass(const char * clsName)----传入完整类名

      2.jclass GetObjectClass(jobject obj)------传入类示例

      3.jclass GetSuperClass(jclass obj)-------传入Class类

 

如: jclass string_class=evn->FindClass("java/lang/String")获取String类

     得到java类后,访问java的属性或方法首先还要在本地代码中获取java属性的jfieldID和java方法的jmethodID才能进行使用。

    使用JNIEvn的

                  1.GetFieldID/GetMethodID来获取非静态的属性和方法

                  2.GetStaticFieldID/GetStaticMethodID来获取静态的属性和方法

 

获取属性参数:(类,属性名,属性签名)

 

获取方法参数:(类,方法名,方法签名)

 

我们都知道java能对方法进行重载,为了准确获取对应的方法和属性,jni引入了Sign(签名),具体如下:




 

获取到java属性的ID后,就可获取和修改java的属性了,非静态属性可调用

Set/GetIntFieldSet/GetBooleanFieldSet/GetDoubleField

Set/GetFloatField

Set/GetLongField

Set/GetShortField

Set/GetObjectField-----------对应数组等

静态属性可调用

Set/GetStaticIntFieldSet/GetStaticBooleanFieldSet/GetStaticDoubleField

Set/GetStaticFloatField

Set/GetStaticLongField

Set/GetStaticShortField

Set/GetStaticObjectField

 

下面举实例

1.调用java属性

java代码如下,在本地方法sayhello里修改其属性score

package com.example;


public class jni_test {

	//在本地方法sayHello里修改score的值
	public native void sayHello();
	
	public float score=99.9f;
	
	static{
		System.loadLibrary("NativeCode");
	}
	
    public static void main(String[] args) {
    	
    	jni_test temp=new jni_test();
    	
    	temp.sayHello();
    	//输出temp的score属性的值
    	System.out.println("score: "+temp.score);
		
	}
}

 

c++本地方法实现的代码:

#include"com_example_jni_test.h"
#include<iostream>
using namespace std;

JNIEXPORT void JNICALL Java_com_example_jni_1test_sayHello(JNIEnv * evn, jobject obj)
{
	//获取java的Class--sayHello方法是非静态方法,所以此时obj是调用这个函数的实例,即java中的实例temp
	jclass my_class=evn->GetObjectClass(obj);
	//jclass my_class=evn->FindClass("com/example/jni_test");也可以获取Class
	//获取java的score属性的FieldID
	jfieldID score_id=evn->GetFieldID(my_class,"score","F");//(类,属性名.签名)
	//根据FieldID获取属性
	jfloat score=evn->GetFloatField(obj,score_id);//(实例对象,属性ID)
	//修改java的temp的score的值
	evn->SetFloatField(obj,score_id,88.8);

}

 编译生成dll加入PATH即可.

 

运行结果为:



 

至此,成功获取java对象的属性并修改其属性的值

 

2.调用java方法

在本地方法里调用Max_num,输出最大值

java代码:

package com.example;


public class jni_test {

	//在本地方法sayHello里调用Max_num方法
	public native void sayHello();
	
	//返回最大值
	public void Max_num(int ok,int ok1)
	{
		if(ok>ok1)
			System.out.println("最大值是: "+ok);
		else 
			System.out.println("最大值是: "+ok1);
	}
	
	static{
		System.loadLibrary("NativeCode");
	}
	
    public static void main(String[] args) {
    	
    	jni_test temp=new jni_test();
    	
    	temp.sayHello();//输出最大值	
	}
}

 

 

本地方法C++实现

#include"com_example_jni_test.h"
#include<iostream>
using namespace std;

JNIEXPORT void JNICALL Java_com_example_jni_1test_sayHello(JNIEnv * evn, jobject obj)
{
	//获取java的Class--sayHello方法是非静态方法,所以此时obj是调用这个函数的实例,即java中的实例temp
	jclass my_class=evn->GetObjectClass(obj);
	//jclass my_class=evn->FindClass("com/example/jni_test");也可以获取Class
	//获取java的Max_num方法的ID
	jmethodID max_id=evn->GetMethodID(my_class,"Max_num","(II)V");//(类,属性名.签名)	
	//调用Max_num方法--Call<type>Method--type函数返回值
	evn->CallVoidMethod(obj,max_id,100,123);//(对象,方法ID,参数...)


}

 

运行结果: