之前实现了简单的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,参数...) }
运行结果: