今天继续记录JNI学习过程,今日内容为本地代码调用Java代码。
在刚开始的那篇中,我们在c++代码中输出了一句Hello JNI来开启JNI学习之旅,顺便从中也知道了在Java中用native方法可以调用C++中的代码。
其实今天所看到的也可以反过来用,在本地代码(也就是C++代码)中同样可以调用Java中的代码。
延续上一篇记录的笔记,我们通过javah工具生成的c++头文件中,会发现如下的函数声明:
JNIEXPORT void JNICALL Java_com_wang_TestNative_sayHello(JNIEnv* ,jobject)
这个声明中有两个参数需要传递,而这两个参数就和Java代码有关。具体来看c++源文件中的代码:
JNIEXPORT void JNICALL Java_com_wang_TestNative_sayHello(JNIEnv* env ,jobject obj){
//.........
}
JNIEnv指针类型的参数实际上代表了Java环境。通过这个JNIEnv*指针,就可以对Java端的代码进行操作,如创建Java类的对象,调用Java的方法,获取Java对象的属性等等,有很大的作用。JNIEnv*有很多函数可以用,像:
NewObject/NewString/New<TYPE>Array; //创建Java的对象用
Get/Set<TYPE>Field; //获取或设置某一个对象的属性
Get/SetStatic<TYPE>Field;
Call<TYPE>Method/CallStatic<TYPE>Method等等很多函数。
jobject是一个指向java对象的引用,这个本地方法是非静态方法,因此这里代表了用了这个本地方法的java实例。
接下来看看jclass的取得:为了能够在C/C++中使用Java类。JNI.h头文件定义了jclass类型来表示Java中的Class类,可以通过下面函数取得:
jclass FindClass(const char* clsName);
jclass GetObjectClass(jobject obj);
jclass GetSuperClass(jclass obj);
另外在c++代码中访问Java端的代码,常见的就是获得类的属性和调用类方法,因此在头文件中会发现jfieldID和jmethodID两个来代表java端的属性和方法。
要访问java属性时要先取得Java属性的jfieldID,然后才能在本地代码访问java属性,同样的要先取得Java属性的jmethodID才能进行Java方法调用。
这下面首先来介绍获取属性的用法。。。
先在java代码中写一个属性:
public int number = 10;
因为是接着上次的那个工程,本有一个sayHello()方法,因此就在对于的c++中的Java_com_wang_TestNative_sayHello方法中来调用java中德number那个属性。
接下来就是在c++代码中书写了:
JNIEXPORT void JNICALL Java_com_wang_TestNative_sayHello
(JNIEnv *env, jobject obj){
//cout<<"Hello JNI!"<<endl;
jclass class_TestNative = env->GetObjectClass(obj);
jfieldID id_number = env->GetFieldID(class_TestNative,"number","I");
jint number = env->GetIntField(obj,id_number);
cout<<number<<endl;
env->SetIntField(obj,id_number,100L);
}
其中GetObjectClass(obj)就是获得TestNative类了,获得类后,就可以通过jfieldID获得number属性的id,GetFieldID中的“number”对应java中要获得的那个属性的名字,“I”对应的是属性的类型int。。然后再用GetIntField获得number属性的值。
SetIntField当然就是设置java中number属性值的方法了,这里将它设置为100.因为java中的int类型对应c++中的长整型类型,所以要写100L。
然后编译通过。
最后在java中的main函数里写上如下代码测试一下:
public static void main(String[] args) {
// TODO Auto-generated method stub
TestNative test = new TestNative();
test.sayHello();
System.out.println(test.number);
}
这样就会发现最后的输出结果,第一个是10,第二个是100.
也就是第一个是用c++代码输出,证明取得了Java中的number属性,第二个是用java代码输出,是100,说明通过c++代码改变了number的值。