JNI技术基础(2)——从零开始编写JNI代码
书接上文: 《JNI技术基础(1)——从零开始编写JNI代码》
2.编译源程序HelloWorld.java并生成HelloWorld.class
3.生成头文件HelloWorld.h
在Linux控制台输入命令:javah –jni HelloWorld 生成HelloWorld.h头文件
//HelloWorld.h /* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */ #ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: print
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_print
(JNIEnv *, jobject); #ifdef __cplusplus
}
#endif
#endif
这个头文件中便告诉了我们需要用C/C++实现的函数的原型,即
JNIEXPORT void JNICALL Java_HelloWorld_print ( JNIEnv * env, jobject obj)
我们只需要按照这种格式完成其函数体的实现即可,函数名的格式:
Java_类名_函数名
参数env代表java虚拟机环境,Java传过来的参数和c有很大的不同,需要调用JVM提供的接口来转换成C类型的,就是通过调用env方法来完成转换的。
参数obj代表调用的对象,相当于c++的this。当c函数需要改变调用对象成员变量时,可以通过操作这个对象来完成。
4.实现C/C++函数
这块儿有点偷懒,并没有逐个字母去敲,而是通过拷贝头文件的方法,然后删除头文件中的无用信息,填充函数体的方法来创建HelloWorld.c文件,主要是因为JNI函数名都比较复杂,害怕疏忽敲错某个字符,或者少实现了某个函数,见谅。
//HelloWorld.c #include <jni.h>
#include <stdio.h>
#include "HelloWorld.h" /*
* Class: HelloWorld
* Method: print
* Signature: ()V
*/ JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject){
printf("Hello World!\n");
}
由上面可以看出,函数体的实现和普通的C/C++函数完全相同,不同的只是函数原型的格式。
需要注意的一点就是记得添加2个头文件:jni.h和HelloWorld.h 。
5.编译生成库文件
gcc -I/usr/lib/jvm/java-1.5.0-sun-1.5.0.22/include/linux/
-I/usr/lib/jvm/java-1.5.0-sun-1.5.0.22/include/
-fPIC -shared -o libHelloWorld.so HelloWorld.c
在编译的时候需要注意的就是记得加上java的两个路径,该路径根据你的java环境的实际安装路径而设置,其余的和编译普通的动态库方法相同。
第一个红色方框中圈出了我们经常范的一个错误,就是没有填写JNI函数的两个形参,虽然我们这里用不到它们,但是也必须写上,否则无法通过编译。
//HelloWorld.c #include <jni.h>
#include <stdio.h>
#include "HelloWorld.h" /*
* Class: HelloWorld
* Method: print
* Signature: ()V
*/ JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *env, jobject obj){
printf("Hello World!\n");
}
6.运行Java程序
方框圈出了两个经常范的错误,第一个错误产生的原因是找不到刚刚生成的C/C++动态库,需要手动指定库的路径,当然也可以把该库拷贝到系统库文件目录中。
手动指定动态库路径的方法是使用参数 -Djava.library.path
java –Djava.library.path = "." HelloWorld
第二个错误产生的原因是使用参数时,"="的前面或者后面使用了空格,去掉等号前后的空格即可。
OK,大功告成,终于看到久违的HelloWorld!
7.附录:一个简单的例程
<1>. MyTools.java
//MyTools.java class MyTools{ private native int myAdd(int x, int y);
private native int mySub(int x, int y); public static void main(String[] args){ int a = 5;
int b = 7;
int c = new MyTools().myAdd(a, b);
int d = new MyTools().mySub(a, b);
System.out.println(a + " + " + b + " = " + c);
System.out.println(a + " - " + b + " = " + d);
} static{
System.loadLibrary("MyTools");
} }
<2>. 自动生成MyTools.h头文件
//MyTools.h /* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class MyTools */ #ifndef _Included_MyTools
#define _Included_MyTools
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: MyTools
* Method: myAdd
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_MyTools_myAdd
(JNIEnv *, jobject, jint, jint); /*
* Class: MyTools
* Method: mySub
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_MyTools_mySub
(JNIEnv *, jobject, jint, jint); #ifdef __cplusplus
}
#endif
#endif
<3>. 函数体的C/C++实现myTools.c
//MyTools.c #include <jni.h>
#include "MyTools.h" /*
* Class: MyTools
* Method: myAdd
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_MyTools_myAdd (JNIEnv *env, jobject obj, jint x, jint y){
return (x + y);
} /*
* Class: MyTools
* Method: mySub
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_MyTools_mySub (JNIEnv *env, jobject obj, jint x, jint y){
return (x - y);
}
运行结果:
说明:
1.大多数情况下,JNI都是在Android开发中使用,本文的目的是使用最简单的语言描述出JNI最基本、最简单的使用流程,所以并没有使用Android框架,Android框架中的一大堆东西会阻挡我们的视线,无法专注于对JNI本身的了解,而Android下JNI的使用流程和Java是基本相同的,后面会有专门的篇幅介绍Android下JNI编程。
2.此处实现了使用JNI传递简单的参数x和y。
3.通过上面两个例子,相信大家已经可以写出自己的简单的 JNI 应用,但是整个 JNI 系统相当复杂,尤其是参数和返回值的传递方面,后面会有专门篇幅详细介绍。
< end >
JNI技术基础(2)——从零开始编写JNI代码的更多相关文章
- JNI技术基础(1)——从零开始编写JNI代码
众所周知,Java程序的最大特点就是其跨平台的特性,编写的上层应用程序可以不加任何修改甚至不用重新编译而运行于不同的平台上,然而,Java本身也存着这一个弊端,那就是性能上相对要差一些,在对性能要求比 ...
- 技术转载:Jni学习四:如何编写jni方法
转载:http://blog.chinaunix.net/u1/38994/showart_1099528.html 一.概述: 在这篇文章中将会简单介绍如何编制一些简单的JNI 方法.我们都知道JN ...
- Android Studio1.4.x JNI开发基础-基本环境配置
从Eclipse时代到Android Studio普及,开发工具越来越好用.早些时候还需要安装Cygwin工具,从Android Studio1.3以后,在Android 环境开发JNI程序搭建开发环 ...
- 【转】Android 学习笔记——利用JNI技术在Android中调用、调试C++代码
原文网址:http://cherishlc.iteye.com/blog/1756762 在Android中调用C++其实就是在Java中调用C++代码,只是在windows下编译生成DLL,在And ...
- 【Android高级】NDK/JNI编程技术基础介绍
作为一个Andoird的Java程序猿,会受到Java语言的局限.由于作为一面门向对象的语言不能像C/C++那样轻易调用与硬件有关的操作.因此JNI就搭建了这样一个桥梁,使Java和C/C++语言之间 ...
- [转][android][利用JNI技术在Android中调用、调试C++代码]
在Android中调用C++其实就是在Java中调用C++代码,只是在windows下编译生成DLL,在Android中会生成Linux系统下的.so文件(好吧,其实我基本没用过Linux). 没写过 ...
- Android JNI编程(八)——体验AS2.2.2编写Jni程序、Java调C、C调Java函数、将C代码中的Log打印至Logcat
版权声明:本文出自阿钟的博客,转载请注明出处:http://blog.csdn.net/a_zhon/. 目录(?)[+] 不得不说在AS2.2以上的版本进行开发就一个字——爽,在2.0上使用jni出 ...
- windows和linux环境下java调用C++代码-JNI技术
最近部门做安卓移动开发的需要调C++的代码,困难重重,最后任务交给了我,查找相关资料,没有一个教程能把不同环境(windows,linux)下怎么调用说明白的,自己在实现的过程中踩了几个坑,在这里总结 ...
- 使用jni技术进行android应用签名信息核查及敏感信息保护
近期业余时间写了一款应用<摇啊摇>,安智.安卓.360等几个应用商店已经陆续审核通过并上线.从有想法到终于将产品做出来并公布,断断续续花了近二个半月的业余时间,整体来讲还算顺 ...
随机推荐
- 定位一组对象-checkbox 、radiobutton
webdriver 可以很方便的使用find_element 方法来定位某个特定的对象,不过有时候我们却需要定位一组对象,WebElement 接口同样提供了定位一组元素的方法find_element ...
- Multiple annotations found at this line: - The content of element type "mapper" must match "EMPTY". - Attribute "namespace" must be declared for element type "mapper".
今天在mybatis的mapper映射配置文件中遇到了这样的问题,困扰了我3个小时: Multiple annotations found at this line: - The content of ...
- iOS真机调试问题-App installation failed,The maximum number of apps for free development profiles has been reached.
The maximum number of apps for free development profiles has been reached. 源引:http://www.jianshu.com ...
- C++主要数据类型在计算机中所占字节大小
遇到了数据存储的大端和小端问题,这你妹的看的一头雾水,发现我基本知识严重匮乏啊,先了解C++各数据类型在自己机子上占多少字节吧,以及这些数据类型所占字节大小与神马有关.各种查资料然后写代码检验,小结于 ...
- expdp小记
一.10.2.0.5要求expdp导出a用户b表空间下的数据. expdp \'/ as sysdba\' directory=mydir dumpfile=1.dmp schemas=a exclu ...
- 在UITableViewStylePlain情况下sectionHeader可以与tableview一起滑动的解决方法
-(void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat sectionHeaderHeight = ; ) { scrollVi ...
- Int16, Int32, Int64 范围
Int16, 等于short, 占2个字节. -32768 32767 Int32, 等于int, 占4个字节. -2147483648 2147483647 Int64, 等于long, 占8个字节 ...
- 1044. Shopping in Mars (25)
分析: 考察二分,简单模拟会超时,优化后时间正好,但二分速度快些,注意以下几点: (1):如果一个序列D1 ... Dn,如果我们计算Di到Dj的和, 那么我们可以计算D1到Dj的和sum1,D1到D ...
- jQuery中.attr()和.prop()的区别
之前学习jQuery的时候,学习到了两种取得标签的属性值的方法:一种是elemJobj.attr(),另一种是elemJobj.prop().而在学习JS的时候,只有一种方法elemObj.getAt ...
- android 区分wifi是5G还是2.4G
http://bbs.csdn.net/topics/391033966?page=1 我一开始看这帖子,找不到答案,为了后来的人,我来回复吧.WifiManager wifiManager = (W ...