第二讲主要是介绍JNI中提供的调用和修改以及其他一些操作java代码的方法,具体如下
1、Java工具生成的C/C++函数声明中,可以看到两个参数:
//对 com_fomagic_TestNative.h 中声明的方法定义
JNIEXPORT void JNICALL Java_com_fomagic_TestNative_sayHello (JNIEnv *evn, jobject obj)
{
cout<<"Hello World !"<<endl;
}
JNIEnv *env
JNIEnv类型可以看做是Java环境,通过这个JNIEnv* 指针,可以对Java端的代码进行操作,
JNIEnv的指针会被JNI传入到本地方法的实现函数中来对Java端的代码操作
例如:创建Java类的对象,调用Java对象的方法,获取Java对象的属性等
<TYPE> 代表数据类型
函数:NewObject/NewString/New<TYPE>Array //创建数组
Get/Set<TYPE>Field //获取/设定变量属性
Get/SetStatic<TYPE>Method/CallStatic<TYPE>Method … //对方法进行操作
我们可以在jni.h 头文件中找到所有定义的方法:
struct JNIEnv_; //定义所有方法的结构体
typedef JNIEnv_ JNIEnv;
………………
struct JNIEnv_ {
const struct JNINativeInterface_ *functions;
………………
jclass FindClass(const char *name) {
return functions->FindClass(this, name);
}
………………
jint GetIntField(jobject obj, jfieldID fieldID) {
return functions->GetIntField(this,obj,fieldID);
}
}
jobject obj
同样也可以在jni.h中看到对jobject的定义
表示传进来的参数为调用该方法的对象,如果是 静态native函数,则表示native方法坐在的类
2、Java类型在C/C++中的映射关系
这个没有什么要说的,直接看图,就是JNI 为了我方便使用定义的别名
3、jclass的取得
为了可以在C/C++中使用Java类 jni.h头文件中专门定义了jclass类型来表示Java中的Class类
JNIEnv类中有如下几个函数取得jclass
jclass FindClass(const char* clsName);
jclass GetObjectClass(jobject obj);
jclass GetSuperClass(jclass obj);
FindClass会在classpath系统环境变量下找类
传入完整类名,注意包与包之间用”/” 而不是”.”来连接
如:jclass cls_string=env->FindClass(“java/lang/String”);
4、访问Java类中的属性和方法
在C/C++本地代码中访问Java端的代码,一个常见的应用就是获取类的属性和调
用类的方法,为了在C/C++中表示属性和方法,JNI在jni.h 头文件中定义了
jfieldID、jmethodID 类型来分别代表Java端的属性和方法
在访问设置Java 属性 和 方法 时,首先在本地代码获取代表Java属性的jfieldID 和jmethodID 然后进行Java属性和方法的操作
JNIEnv中 GetFieldID/GetMethodID GetStaticFieldID/GetStaticMethodID 获取
如:env->GetMethodID(data_Clazz,”<int>”,”()V”); // ()V指无返回类型void,下面讲到
5、Sign是什么?
例如TestNative.java中有两个重载方法:
package com.fomagic;
public class TestNative {
public void function(int i){
System.out.println("Integer: "+i);
}
public void function(double d){
System.out.println("Double: "+d);
}
}
当在C++中调用其中一个函数的时候,就需要按照以下步骤:
1、获取函数所在类 jclass clazz_Testnative=env->FindClass(“com.fomagic.TestNative”);
2、获取方法的 jmethodID 来调用方法 jmethodID id_func =env->GetMethodID (clazz_Testnative,”function”,” (I)V”);
->GetMethodID (clazz_Testnative,”function”,” (D)V”);
其中 通过指定函数的参数类型和返回值类型 来返回 jmethodID,从而对应的函数,这就是sign
以下是对应类型:
6、使用javap命令生成签名
JDK中提供了 javap工具来查看类的声明,可以输出每个方法与属性的签名
package com.fomagic;
import java.util.Date;
public class TestNative {
public native void sayHello(); //C++本地代码实现
public static void main(String[] args) {
System.loadLibrary("NativeCode");//加载动态链接库,不能加 .dll
TestNative test=new TestNative();
test.sayHello();
}
public int property;
public int function(int foo,Date date, int[] arr){
return 0;
}
}
我们对上面代码通过 javap 工具直接生成方法和属性的签名:
1、命令行定位到该类的绝对路径 cd TestNativeCode\bin 目录
2、执行 javap -s -private com.fomagic.Testnative
javap -s -p… [完整类名]
注:private获取全部权限的成员、public获取public修饰的成员 (即 获取大于或等于自己权限的成员方法或属性)