上一篇文章给大家介绍了怎样使用JNI来调用Native代码,在被调用的C/C++函数中也可以反过来访问Java程序中的类,接下来给大家讲解怎样使用Native代码访问Java代码。
.h头文件分析
在上一篇文章中我们使用javah 命令生成的头文件(.h)中有两个非常重要的参数,具体代码如下:
JNIEXPORT void JNICALL Java_com_jony_nativetest_TestNative_sayHello(JNIEnv *, jobject);
参数说明:
JNIEnv类型实际上代表了Java环境。通过这个JNIEnv*指针就可以对Java端的代码进行操作。例如,创建Java类的对象,调用Java对象的方法,获取Java对象的属性等等。
JNIEnv的指针会被JNI传入到本地方法(Native代码)的实现函数中来对Java端的代码进行操作。
JNIEnv类中有很多函数可以使用:
NewObject/NewString/New<TYPE>Array
Get/Set<TYPE>Field
Get/SetStatic<TYPE>Field
Call<TYPE>Method/CallStatic<TYOE>Method等许多函数;
jobject类型指向java对象的引用;该参数使用有两种情况:非静态方法调用(实例:publicnativevoid sayHello();)>> 与该方法相关联的引用——实例对象;
静态方法调用(实例:public native static void sayHello();)>> 代表指向调用类的对象(ClassName.class)。
Java类型在C/C++中对应映射关系如图所示:
获取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");//类完整路径名
访问Java类中的属性和方法
在C/C++本地代码中访问Java端的代码,常见的应用就是获取类的属性和调用类的方法。为了在C/C++中表示属性和方法,JNI在jni.h头文件中定义了jfieldID,jmethodID类型来分别代表Java端的属性和方法。
我们在访问或是设置Java属性的时候,首先就要现在本地代码(Native Code)取得代表该Java属性的jfieldID,然后才能在本地代码(Native Code)进行Java属性操作。同样,当我们需要调用Java端的方法时,也是需要取得代表该方法的jmethodID才能进行Java方法调用。
API方法:
使用JNIEnv的 GetFieldID/GetMethodID 或 GetStaticFieldID/GetStaticMethodID来获相应的jfieldID和jmethodID
具体参数及实例如图所示:
从上图中大家可以看到每个方法都有三个参数:
第一个参数是jclass类型,我们可以通过上面所述的方式获得jclass对象;
第二个参数是属性名或方法名;
第三个参数是sign(签名)——用于指定取得属性或方法的类型。
接下来重点讲解一个sign参数的生成方式:
类型对应签名信息如图所示:
sign签名图解:
到此为止大家了解了签名的生成规则,但是非常复杂难以记忆,因此java提供了javap工具来查看类签名信息。
javap命令查看类签名信息
javap命令的使用方式如图所示:
使用javap命令来生成签名
JDK提供了一个工具javap来查看一个类的声明。其中就可以设置输出每个方法/属性的签名。
使用方法:
javap -s -p [full Class Name]
-s 表示输出签名信息
-p 同-private,输出包括private访问权限的成员信息
实例代码(TestNative.java):
package com.jony.nativetest;
import java.util.Date;
public class TestNative {
public int property;
public native void sayHello();
public int function(int i,Date date,int[] arr){
System.out.println("function");
return 0;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.loadLibrary("NativeCode01");// 加载动态链接库
TestNative testNative = new TestNative();
testNative.sayHello();
}
}
编译该java文件后,进入工程目录下的bin目录,执行以下命令:
javap -s -p com.jony.nativetest.TestNative 后运行结果如图所示:
至此,怎么获得签名信息已经完成,谢谢大家的支持!
下一篇文章将给大家介绍本地代码怎样操作Java属性……