JNI编程Demo----Java程序调用C&C++编译好的库文件

来源:互联网 发布:centos7源码安装nginx 编辑:程序博客网 时间:2024/06/15 06:19

JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。下面用一个Demo实现通过JNI,Java如何调用C&C++的库文件(Windows下是dll文件,Linux下是so文件)。

本文在Windows下实现,因此调用的是dll文件,期间也会说明linux下调用so文件有什么不同之处,环境如下:
- 操作系统:Win10 Pro
- JDK:1.7(1.8也完全ok)
- IDE:Jetbrains IDEA 2016.3 Community

一、安装GCC环境
Windows下,一般选择安装MinGW,下载地址:下载地址,安装好后,将MinGW安装目录下的bin目录加入PATH中,然后打开命令行,输入gcc -v,出现如下信息即证明安装完成:
这里写图片描述

二、JNI Demo

  • 首先用IDEA创建一个Java工程,在src目录下创建一个包,包名为cn.hust.demo,如图:
    这里写图片描述
    在该包下编写类TestAdd,我们要实现的功能是两个数相加:

    package cn.hust.demo;// Created by LCJ on 2017.7.21.public class TestAdd {    static {        System.loadLibrary("Add");    }    private native int add(int a, int b);    public static void main(String[] args) {        int c = new TestAdd().add(3, 4);        System.out.println("Result is: " + c);    }}

    方法System.loadLibrary()用来加载dll(windows)或so(Linux)库,只需名称即可,无需加入文件名后缀(.dll或.so)。native关键字将函数add(int a, int b)声明为本地函数,由C/C++实现。具体的实现就在Add.dll(Windows平台)或libAdd.so(Linux平台)中。注意,在Linux平台下,so文件前面要有“lib”前缀(但是System.loadLibrary()的参数仍然和Windows下一样,不用带“lib”),否则会找不到库文件。

  • 生成头文件
    首先将TestAdd.java编译一下,出现TestAdd.class:
    这里写图片描述
    然后配置生成头文件的命令:
    File–>Settings–>Tools–>External Tools,点击右边的“+”号,如下填写:
    这里写图片描述
    Name为“Generate Header File”,上图中Tool Settings部分的填写:
    Program:$JDKPath$/bin/javah
    Parameters:-jni -classpath $OutputPath$ -d ./jni $FileClass$
    Working Dictionary:$ProjectFileDir$
    如此配置好后,在TestAdd.java文件上右键,选择External tools–>Generate Header File:
    这里写图片描述
    即生成了头文件如下:
    这里写图片描述
    代码如下:

    /* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class cn_hust_demo_TestAdd */#ifndef _Included_cn_hust_demo_TestAdd#define _Included_cn_hust_demo_TestAdd#ifdef __cplusplusextern "C" {#endif/* * Class:     cn_hust_demo_TestAdd * Method:    add * Signature: (II)I */JNIEXPORT jint JNICALL Java_cn_hust_demo_TestAdd_add  (JNIEnv *, jobject, jint, jint);#ifdef __cplusplus}#endif#endif

    在此代码中,函数命名为Java_<包>_<类名>_<函数名>,参数中除前两个参数外,后面两个是add函数的参数类型,jint对应int型。

  • 编写C语言文件
    在jni目录下编写add.c文件:
    这里写图片描述
    代码:

    #include <jni.h>#include <stdio.h>#include "cn_hust_demo_TestAdd.h"JNIEXPORT jint JNICALL Java_cn_hust_demo_TestAdd_add(JNIEnv *env, jobject o, jint a, jint b){jint c = a + b;printf("The sum of %d + %d is: %d", a, b, c);return c;}
  • 编译C语言文件,生成dll库
    仍然同生成头文件一样,用IDEA的external tools一键生成dll文件。因此打开external tool配置界面,点击“+”号,创建一个名为“Generate DLL”(如果是Linux环境下,你就命名为“Generate SO”)的tool:
    这里写图片描述
    具体配置如下:
    Program:D:\Program Files\MinGW\mingw64\bin\gcc.exe 即你的gcc目录,Linux下也同样是gcc路径
    Parameters:-Wl,--add-stdcall-alias -I"$JDKPath$\include" -I"$JDKPath$\include\win32" -shared -o ./lib/$FileNameWithoutExtension$.dll ./jni/$FileNameWithoutExtension$.c 注意,如果是Linux环境下,win32要改成linux,dll文件的文件名也要改,前面要加上lib前缀,同时是so文件而非dll文件,命令细节也要更改,最终如此:-I"$JDKPath$\include" -I"$JDKPath$\include\linux" -fPIC -shared -o ./lib/lib$FileNameWithoutExtension$.so ./jni/$FileNameWithoutExtension$.c
    Working dictionary:$ProjectFileDir$
    配置好后,在工作目录下新建lib文件夹,然后右键Add.c,选择external tools中的“Generate DLL”,在lib目录下生成DLL文件:
    这里写图片描述
    这里写图片描述

  • 运行Java程序,得出结果
    此时,运行一开始的java程序会报错找不到库文件:
    这里写图片描述
    这时,需要在运行参数中配置如下:
    这里写图片描述
    将VM options中加入:
    -Djava.library.path=I:\IDEAWorkspace\JNI\TestJNIDemo\lib
    即library path指向DLL文件所在目录即可。
    此时再运行java程序,即得出正确结果:
    这里写图片描述

三、附注
本文展示了生成头文件、写C语言程序和生成库文件的全过程Demo,一般情况下,是直接拿到库文件进行调用的,因此前面的过程可以略去,只需知道该库文件哪些函数可以调用,直接用Java进行调用即可。

原创粉丝点击