zoukankan      html  css  js  c++  java
  • 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!
    ");
    }

    由上面可以看出,函数体的实现和普通的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!
    ");
    }
    

      

    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 >

     

     

  • 相关阅读:
    大臣的旅费 Apare_xzc 求树的直径 蓝桥杯
    连号区间数 Apare_xzc
    js盒模型
    js仿真进度条
    JS卷动事件
    json对象读取
    button属性及兼容性处理
    js图片跟随效果
    商城倒计时JS怎么做
    计算某天距离现在日期的差值
  • 原文地址:https://www.cnblogs.com/mylizh/p/3976096.html
Copyright © 2011-2022 走看看