书接上文: 《JNI技术基础(1)——从零开始编写JNI代码

2.编译源程序HelloWorld.java并生成HelloWorld.class

3.生成头文件HelloWorld.h

在Linux控制台输入命令:javah –jni HelloWorld 生成HelloWorld.h头文件

  1. //HelloWorld.h
  2.  
  3. /* DO NOT EDIT THIS FILE - it is machine generated */
  4. #include <jni.h>
  5. /* Header for class HelloWorld */
  6.  
  7. #ifndef _Included_HelloWorld
  8. #define _Included_HelloWorld
  9. #ifdef __cplusplus
  10. extern "C" {
  11. #endif
  12. /*
  13. * Class: HelloWorld
  14. * Method: print
  15. * Signature: ()V
  16. */
  17. JNIEXPORT void JNICALL Java_HelloWorld_print
  18. (JNIEnv *, jobject);
  19.  
  20. #ifdef __cplusplus
  21. }
  22. #endif
  23. #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函数名都比较复杂,害怕疏忽敲错某个字符,或者少实现了某个函数,见谅。

  1. //HelloWorld.c
  2.  
  3. #include <jni.h>
  4. #include <stdio.h>
  5. #include "HelloWorld.h"
  6.  
  7. /*
  8. * Class: HelloWorld
  9. * Method: print
  10. * Signature: ()V
  11. */
  12.  
  13. JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject){
  14. printf("Hello World!\n");
  15. }

由上面可以看出,函数体的实现和普通的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函数的两个形参,虽然我们这里用不到它们,但是也必须写上,否则无法通过编译。

  1. //HelloWorld.c
  2.  
  3. #include <jni.h>
  4. #include <stdio.h>
  5. #include "HelloWorld.h"
  6.  
  7. /*
  8. * Class: HelloWorld
  9. * Method: print
  10. * Signature: ()V
  11. */
  12.  
  13. JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *env, jobject obj){
  14. printf("Hello World!\n");
  15. }

  

6.运行Java程序

方框圈出了两个经常范的错误,第一个错误产生的原因是找不到刚刚生成的C/C++动态库,需要手动指定库的路径,当然也可以把该库拷贝到系统库文件目录中。

手动指定动态库路径的方法是使用参数 -Djava.library.path

java –Djava.library.path = "."  HelloWorld

第二个错误产生的原因是使用参数时,"="的前面或者后面使用了空格,去掉等号前后的空格即可。

OK,大功告成,终于看到久违的HelloWorld!

7.附录:一个简单的例程

<1>. MyTools.java

  1. //MyTools.java
  2.  
  3. class MyTools{
  4.  
  5. private native int myAdd(int x, int y);
  6. private native int mySub(int x, int y);
  7.  
  8. public static void main(String[] args){
  9.  
  10. int a = 5;
  11. int b = 7;
  12. int c = new MyTools().myAdd(a, b);
  13. int d = new MyTools().mySub(a, b);
  14. System.out.println(a + " + " + b + " = " + c);
  15. System.out.println(a + " - " + b + " = " + d);
  16. }
  17.  
  18. static{
  19. System.loadLibrary("MyTools");
  20. }
  21.  
  22. }

  

<2>. 自动生成MyTools.h头文件

  1. //MyTools.h
  2.  
  3. /* DO NOT EDIT THIS FILE - it is machine generated */
  4. #include <jni.h>
  5. /* Header for class MyTools */
  6.  
  7. #ifndef _Included_MyTools
  8. #define _Included_MyTools
  9. #ifdef __cplusplus
  10. extern "C" {
  11. #endif
  12. /*
  13. * Class: MyTools
  14. * Method: myAdd
  15. * Signature: (II)I
  16. */
  17. JNIEXPORT jint JNICALL Java_MyTools_myAdd
  18. (JNIEnv *, jobject, jint, jint);
  19.  
  20. /*
  21. * Class: MyTools
  22. * Method: mySub
  23. * Signature: (II)I
  24. */
  25. JNIEXPORT jint JNICALL Java_MyTools_mySub
  26. (JNIEnv *, jobject, jint, jint);
  27.  
  28. #ifdef __cplusplus
  29. }
  30. #endif
  31. #endif

  

<3>. 函数体的C/C++实现myTools.c

  1. //MyTools.c
  2.  
  3. #include <jni.h>
  4. #include "MyTools.h"
  5.  
  6. /*
  7. * Class: MyTools
  8. * Method: myAdd
  9. * Signature: (II)I
  10. */
  11. JNIEXPORT jint JNICALL Java_MyTools_myAdd (JNIEnv *env, jobject obj, jint x, jint y){
  12. return (x + y);
  13. }
  14.  
  15. /*
  16. * Class: MyTools
  17. * Method: mySub
  18. * Signature: (II)I
  19. */
  20. JNIEXPORT jint JNICALL Java_MyTools_mySub (JNIEnv *env, jobject obj, jint x, jint y){
  21. return (x - y);
  22. }

运行结果:

说明:

1.大多数情况下,JNI都是在Android开发中使用,本文的目的是使用最简单的语言描述出JNI最基本、最简单的使用流程,所以并没有使用Android框架,Android框架中的一大堆东西会阻挡我们的视线,无法专注于对JNI本身的了解,而Android下JNI的使用流程和Java是基本相同的,后面会有专门的篇幅介绍Android下JNI编程。
     2.此处实现了使用JNI传递简单的参数x和y。

3.通过上面两个例子,相信大家已经可以写出自己的简单的 JNI 应用,但是整个 JNI 系统相当复杂,尤其是参数和返回值的传递方面,后面会有专门篇幅详细介绍。

< end >

JNI技术基础(2)——从零开始编写JNI代码的更多相关文章

  1. JNI技术基础(1)——从零开始编写JNI代码

    众所周知,Java程序的最大特点就是其跨平台的特性,编写的上层应用程序可以不加任何修改甚至不用重新编译而运行于不同的平台上,然而,Java本身也存着这一个弊端,那就是性能上相对要差一些,在对性能要求比 ...

  2. 技术转载:Jni学习四:如何编写jni方法

    转载:http://blog.chinaunix.net/u1/38994/showart_1099528.html 一.概述: 在这篇文章中将会简单介绍如何编制一些简单的JNI 方法.我们都知道JN ...

  3. Android Studio1.4.x JNI开发基础-基本环境配置

    从Eclipse时代到Android Studio普及,开发工具越来越好用.早些时候还需要安装Cygwin工具,从Android Studio1.3以后,在Android 环境开发JNI程序搭建开发环 ...

  4. 【转】Android 学习笔记——利用JNI技术在Android中调用、调试C++代码

    原文网址:http://cherishlc.iteye.com/blog/1756762 在Android中调用C++其实就是在Java中调用C++代码,只是在windows下编译生成DLL,在And ...

  5. 【Android高级】NDK/JNI编程技术基础介绍

    作为一个Andoird的Java程序猿,会受到Java语言的局限.由于作为一面门向对象的语言不能像C/C++那样轻易调用与硬件有关的操作.因此JNI就搭建了这样一个桥梁,使Java和C/C++语言之间 ...

  6. [转][android][利用JNI技术在Android中调用、调试C++代码]

    在Android中调用C++其实就是在Java中调用C++代码,只是在windows下编译生成DLL,在Android中会生成Linux系统下的.so文件(好吧,其实我基本没用过Linux). 没写过 ...

  7. Android JNI编程(八)——体验AS2.2.2编写Jni程序、Java调C、C调Java函数、将C代码中的Log打印至Logcat

    版权声明:本文出自阿钟的博客,转载请注明出处:http://blog.csdn.net/a_zhon/. 目录(?)[+] 不得不说在AS2.2以上的版本进行开发就一个字——爽,在2.0上使用jni出 ...

  8. windows和linux环境下java调用C++代码-JNI技术

    最近部门做安卓移动开发的需要调C++的代码,困难重重,最后任务交给了我,查找相关资料,没有一个教程能把不同环境(windows,linux)下怎么调用说明白的,自己在实现的过程中踩了几个坑,在这里总结 ...

  9. 使用jni技术进行android应用签名信息核查及敏感信息保护

           近期业余时间写了一款应用<摇啊摇>,安智.安卓.360等几个应用商店已经陆续审核通过并上线.从有想法到终于将产品做出来并公布,断断续续花了近二个半月的业余时间,整体来讲还算顺 ...

随机推荐

  1. java基础:熟悉3种内部类的写法,重点匿名内部类的使用

    一.内部类定义 内部类(nested classes),面向对象程序设计中,可以在一个类的内部定义另一个类.嵌套类分为两种,即静态嵌套类和非静态嵌套类.静态嵌套类使用很少,最重要的是非静态嵌套类,也即 ...

  2. Windows下MongoDB环境搭建

    MongoDB下载 登录MongoDB官网:www.mongodb.org:点击[Download MongoDB]按钮,进入如下所示界面 选择目标操作系统及其版本,比如这里选择的是64位的Windo ...

  3. error C2065: 'INVALID_SET_FILE_POINTER' : undeclared identifier

    Searching MSDN for that constant brings up one result: it's a failure code for SetFilePointer() and ...

  4. 返回绝对值--Math.Abs 方法

    Math.abs()  返回指定数字的绝对值.

  5. Hibernate的多表查询,分装到一个新的实体类中的一个方法

    不知道是否还有其他方法实现,请高人指点. 如果涉及到多张表多字段查询,并且想利用查询出来的字段在界面层构建一个新的实体类,可以使用这种方法: 如果查询出来的多字段中,有多个字段的名字都相同(如想查询出 ...

  6. [Shell]字符截取命令:cut, printf, awk, sed

    ------------------------------------------------------------------------------------------- [cut命令] ...

  7. aix DNS 配置以及网络命令traceroute和nslookup 和 dig 命令

    DNS 域名系统 (DNS) 服务器将 IP 地址解释为其他计算机或网站的域名和地址.如果没有 DNS,您需要在 Web 浏览器中输入 IP 地址.例如,如果您未访问 DNS 并希望查看 IBM 的网 ...

  8. listView获取item的Edit内容,listView中的edit内容在滚动时自动赋值了前面的内容

    Today I am going to explain how to create a ListView with EditText and why will we need a TextWatche ...

  9. Xcode升级更新后,恢复cocoapods以及插件的方法

    今天将手机系统更新到iOS9.3了,在Xcode7.1上做真机调试,提示找不到适合的SDK,才知道必须要升级Xcode才行,于是升级Xcode到7.3. 升级之后遇到很多麻烦,cocoapods没有了 ...

  10. 反射生成SQL语句

    public static int Reg(Model ml) { bool b = true; Visit vt = new Visit(); StringBuilder builder = new ...