调用JNI函数
来源:互联网 发布:淘宝客服提成2个点 编辑:程序博客网 时间:2024/06/06 04:30
写在最前面
在上一篇博客中,讲解了JNI的运行方式以及Java中调用C函数的步骤,本篇博客将讲解在由C语言编写的JNI本地函数中如何控制Java端的代码,主要包括以下内容
创建Java对象
访问类静态成员域
调用类的静态方法
访问Java对象的成员变量
访问Java对象的方法
调用JNI函数的示例程序
在开始之前,我们先大致看一下示例程序的整体架构。整个示例程序由JniFuncMain类(包含本地方法声明)、JniTest对象、libjnifunc.jnilib(包含本地方法的具体实现)三部分组成。
整个示例程序从调用JniFuncMain类的createJniObject()本地方法开始,该方法经由JNI与libjnitest.jnilib中命名为Java_JniFuncMain_createJniObject()的C函数链接在一起。
Java层代码(JniFuncMain.java)
1. JniFuncMain类
1 public class JniFuncMain 2 { 3 private static int staticIntField = 300; 4 5 // 加载本地库 6 static { System.loadLibrary("jnifunc");} 7 8 // 本地方法声明 9 public static native JniTest createJniObject(); 10 11 public static void main(String[] args) 12 { 13 // 从本地代码生成JniTest对象 14 System.out.println("[Java] createJniObject()调用本地方法"); 15 JniTest jniObj = createJniObject(); 16 17 // 调用JniTest对象的方法 18 jniObj.callTest(); 19 } 20 }
2.JniTest类
1 class JniTest 2 { 3 private int intField; 4 5 // 构造方法 6 public JniTest(int num) 7 { 8 intField = num; 9 System.out.println("[java] 调用JniTest对象的构造方法:intField = " + intField); 10 } 11 12 // 此方法由JNI本地函数调用 13 public int callByNative(int num) 14 { 15 System.out.println("[Java] JniTest对象的callByNative(" + num + ")调用"); 16 return num; 17 } 18 19 public void callTest() 20 { 21 System.out.println("[Java] JniTest对象的callTest()方法调用:intField = " + intField); 22 } 23 }
分析JNI本地函数代码
1.JniFuncMain.h头文件
在JniFuncMain.java代码中,仅仅在本地方法createJniObject()进行了声明,接下来,我们用C语言实现它。首先,使用javah命令,生成本地方法的函数原型,命令如下(此命令之前要先编译JniFuncMain.java文件)。
javac JniFuncMain.javajavah JniFuncMain执行以上命令后,生成如下JniFuncMain.h头文件
1 /* DO NOT EDIT THIS FILE - it is machine generated */ 2 #include <jni.h> 3 /* Header for class JniFuncMain */ 4 5 #ifndef _Included_JniFuncMain 6 #define _Included_JniFuncMain 7 #ifdef __cplusplus 8 extern "C" { 9 #endif 10 /* 11 * Class: JniFuncMain 12 * Method: createJniObject 13 * Signature: ()LJniTest; 14 */ 15 JNIEXPORT jobject JNICALL Java_JniFuncMain_createJniObject 16 (JNIEnv *, jclass); 17 18 #ifdef __cplusplus 19 } 20 #endif 21 #endif
仔细查看上面的代码,可以看到createJniObject()本地方法对应的JNI本地函数原型,形式如下
JNIEXPORT jobject JNICALL Java_JniFuncMain_createJniObject (JNIEnv *, jclass);
这个函数原型与我们的Java类JniFuncMain的createJniObject()本地方法相对应。在上一篇博客中,我们知道使用javah命令生成的JNI本地函数原型的第二个参数默认类型为jobject。但观察上面的代码,会发现它的第二个参数类型为jclass,而不是jobject。原因是什么?若想弄清楚这个问题,首先要理解函数原型第二个参数的含义。在上一篇博客中,我们理解到,jobject类型的变量用来保存调用本地方法的对象的引用。那么我们再回过头看看我们本地方法的声明
public static native JniTest createJniObject();这个本地方法被声明为static(静态)方法。在Java中,调用静态方法时,可以不用创建对象,所以通过所在的类直接调用即可,即本地静态方法通过类而非对象进行调用,因此函数原型的第二个参数类型为jclass类型。
2.JniFuncMain.c文件
1 #include "JniFuncMain.h" 2 #include <stdio.h> 3 4 JNIEXPORT jobject JNICALL Java_JniFuncMain_createJniObject(JNIEnv *env, jclass clazz) 5 { 6 jclass targetClass; 7 jmethodID mid; 8 jobject newObject; 9 jstring helloStr; 10 jfieldID fid; 11 jint staticIntField; 12 jint result; 13 14 // 获取JniFuncMain类的staticIntField变量值 15 fid = (*env)->GetStaticFieldID(env,clazz,"staticIntField","I"); 16 staticIntField = (*env)->GetStaticIntField(env,clazz,fid); 17 printf("[CPP]获取JniFuncMain类的staticIntField值\n"); 18 printf(" JniFuncMain.staticIntField = %d\n", staticIntField); 19 20 // 查找生成对象的类 21 targetClass = (*env)->FindClass(env,"JniTest"); 22 23 // 查找构造方法 24 mid = (*env)->GetMethodID(env,targetClass,"<init>","(I)V"); 25 26 // 生成JniTest对象(返回对象的引用) 27 printf("[CPP] JniTest对象生成\n"); 28 newObject = (*env)->NewObject(env,targetClass,mid,100); 29 30 // 调用对象的方法 31 mid = (*env)->GetMethodID(env,targetClass, "callByNative","(I)I"); 32 result = (*env)->CallIntMethod(env,newObject,mid,200); 33 34 // 设置JniObject对象的intField值 35 fid = (*env)->GetFieldID(env,targetClass,"intField","I"); 36 printf("[CPP]设置JniTest对象的intField值为200\n"); 37 (*env)->SetIntField(env,newObject,fid,result); 38 39 // 返回对象的引用 40 return newObject; 41 }
编译
执行如下命令
gcc -dynamiclib -I /Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home/include/ JniFuncMain.c -o libjnifunc.jnilib得到C链接库,
然后执行java JniFuncMain,得到如下结果
[Java] createJniObject()调用本地方法[CPP]获取JniFuncMain类的staticIntField值 JniFuncMain.staticIntField = 300[CPP] JniTest对象生成[java] 调用JniTest对象的构造方法:intField = 100[Java] JniTest对象的callByNative(200)调用[CPP]设置JniTest对象的intField值为200[Java] JniTest对象的callTest()方法调用:intField = 200
达到我们的预期。
0 0
- Jni函数调用
- Jni函数调用大全
- Jni函数调用大全
- JNI函数调用
- Jni函数调用大全
- Jni函数调用
- Jni函数调用
- JNI函数调用
- JNI函数调用大全
- 调用JNI函数
- Jni函数调用 Chap1:JNI完全手册
- Jni函数调用Chap2:JNI-百度百科
- JNI如何调用Java函数
- Android JNI --函数调用大全
- JNI调用java接口函数
- 《Android JNI》05 在JNI中调用Java的函数
- JNI 对象在函数调用中的生命周期
- JNI 对象在函数调用中的生命周期
- MyEclipse 8.5反编译插件jad安装方法
- VS2005 MFC C/C++ 操作excel【网上找了好多列子,都不合适,自己总结一下】
- iOS与网页JS交互
- 怎么让adb识别修改了VID和PID的手机(移动设备)
- 网络通信_UDP客户端以及服务器
- 调用JNI函数
- 在局域网内用自己的机子当服务器让外网访问测试回调
- WebStorm开发工具设置React Native代码智能提醒
- unity3d随笔-5
- SQL Server,MySQL,Oracle三者的区别
- 如何成为高级程序员
- Windows上传文件到centos7服务器
- 【Algothrim】Ant Teams
- CSS基础01