JNI是Java Native Interface的缩写,从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。

目前java与dll交互的技术主要有3种:jni,jawin和jacob。Jni(Java Native Interface)是sun提供的java与系统中的原生方法交互的技术(在windows\linux系统中,实现java与native method互调)。目前只能由c/c++实现。后两个都是sourceforge上的开源项目,同时也都是基于jni技术的windows系统上的一个应用库。Jacob(Java-Com Bridge)提供了java程序调用microsoft的com对象中的方法的能力。而除了com对象外,jawin(Java/Win32 integration project)还可以win32-dll动态链接库中的方法。就功能而言:jni >> jawin>jacob,就易用性而言,正好相反:jacob>jawin>>jni。

Jni程序开发的一般操作步骤如下

  1. 编写java类声明native方法;
  2. 用javah生成c/c++原生函数的头文件;
  3. 编写c/c++代码实现原生函数并编译成库(windows是dll,linux是so);
  4. 通过System.loadLibrary()或System.load()加载生成的库,或则给虚拟机传参(java.library.path)指定库的路径;
  5. java调用native方法进行业务处理;

下面我们按部就班地进行操作(windows下),编写java类声明native方法

项目结构如下如下:

App.java代码如下:

package net.oseye.JniDemo;

public class App
{
public static void main( String[] args )
{
//调用native方法
new Hello().sayHello();
}
} class Hello{
static{
System.loadLibrary("libhello");
} /*
* 声明native方法
*/
public native void sayHello();
}

编译后会生成App.class和Hello.class。

用javah生成c/c++原生函数的头文件

使用命令

D:\workspace4jee\JniDemo\target\classes>javah -jni net.oseye.JniDemo.Hello

生成c/c++头文件 net_oseye_JniDemo_Hello.h:

net_oseye_JniDemo_Hello.h代码:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class net_oseye_JniDemo_Hello */ #ifndef _Included_net_oseye_JniDemo_Hello
#define _Included_net_oseye_JniDemo_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: net_oseye_JniDemo_Hello
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_net_oseye_JniDemo_Hello_sayHello
(JNIEnv *, jobject); #ifdef __cplusplus
}
#endif
#endif

使用c/c++实现native方法

在与net_oseye_JniDemo_Hello.h的目录下建立hello.cpp,代码:

#include <stdio.h>
#include "net_oseye_JniDemo_Hello.h" JNIEXPORT void JNICALL Java_net_oseye_JniDemo_Hello_sayHello
(JNIEnv *, jobject)
{
printf("Hello, world\n");
}

使用gcc编译成dll,命令:

D:\workspace4jee\JniDemo\target\classes>gcc -shared -Wl,--kill-at -I "d:\Program Files\Java\jdk1.7.0_05\include" hello.cpp -o libhello.dll

此时我的D:\workspace4jee\JniDemo\target\classes路径结构如下:

执行Java程序

D:\workspace4jee\JniDemo\target\classes>java -Djava.library.path=. net.oseye.JniDemo.App

输出

Hello, world


以备不时之需的PS:

  1. linux下有非常好用的c/c++编译器gcc,windows下也有移植,貌似大家比较喜欢MinGW,但需要在线安装,因此需要访问公网权限。我使用了TDM-GCC,它可离线安装,它结合了 GCC 工具集中最新的稳定发行版本,包括了自由并开源的 MinGW 或 MinGW-w64 的运行时 APIs,以此创建一个 LIBRE 来替代微软的编译器及其平台 SDK。GCC简单使用教程可查看百度文库
  2. JNI基本类型
    Java类型
    本地类型
    描述
    boolean
    jboolean
    C/C++8位整型
    byte
    jbyte
    C/C++带符号的8位整型
    char
    jchar
    C/C++无符号的16位整型
    short
    jshort
    C/C++带符号的16位整型
    int
    jint
    C/C++带符号的32位整型
    long
    jlong
    C/C++带符号的64位整型
    float
    jfloat
    C/C++32位浮点型
    double
    jdouble
    C/C++64位浮点型
    Object
    jobject
    任何Java对象,或者没有对应java类型的对象
    Class
    jclass
    Class对象
    String
    jstring
    字符串对象
    Object[]
    jobjectArray
    任何对象的数组
    boolean[]
    jbooleanArray
    布尔型数组
    byte[]
    jbyteArray
    比特型数组
    char[]
    jcharArray
    字符型数组
    short[]
    jshortArray
    短整型数组
    int[]
    jintArray
    整型数组
    long[]
    jlongArray
    长整型数组
    float[]
    jfloatArray
    浮点型数组
    double[]
    jdoubleArray
    双浮点型数组
  3. error: parameter name omitted
    如果你用c实现javah生成的头文件,可能会遇到这个这个问题,这是由于C与C++的细微区别造成的:

    • 在函数声明中:无论是C还是在C++,都可以省略形式参数名。但是,通常都不建议省略形式参数名.
    • 在函数实现中:
      1. 当需要使用形式参数的时候,显然,必须给形式参数命名。
      2. 当不需要使用形式参数的时候,C与C++有微小差异:
        C不能省略形式参数名, 即使不使用。
        C++可以省略形式参数名,如果不使用。并且在C++中,如果给不使用的形式参数命名,可能会得到一个警告。

    由于使用javah生成的头文件是省略形参的,如果你直接拷贝函数定义到实现中,而源文件保存成c而非cpp,就会出现这个错。

  4. java.lang.Unsatisfie.lang.UnsatisfiedLinkError  no XXXXX in java.library.path
    报这个异常主要是找不到你的库(dll或so)文件,你可以使用-Djava.library.path指定库文件地址,或者你通过System.getProperty("java.library.path")获取默认java.library.path地址,把库文件拷贝到里面去。
  5. java.lang.UnsatisfiedLinkError: XXXclass.XXXmethod()
    这个错误是 在这个dll里找不到方法的声明,网上说是@符号的问题 ,主要有三种解决方法:
    1. 第1种方法:

      gcc -Wl,--kill-at -shared -o jnihello.dll Native.c

      这种方法生成不带@的函数声明

    2. 第2种方法:
      gcc -Wl,--add-stdcall-alias -shared -o jnihello22.dll Native.c 

      这种方法会生成2个函数声明,一个是带@的 一个是不带@的。

    3. 第3种方法: 在你的本地方法的头文件中中的函数前面加上下划线,比如以前是 
      JNIEXPORT void JNICALL Java_net_oseye_JniDemo_Hello_sayHello(JNIEnv *, jobject);

      现在改成

      JNIEXPORT void JNICALL _Java_net_oseye_JniDemo_Hello_sayHello(JNIEnv *, jobject);

      同时你的实现的cpp文件或者c文件里的函数头也要一致 前面有下划线。

JNI之C初探的更多相关文章

  1. JNI基础概念以及原理-2016.01.11

    Java到C数据类型转换 1 基础类型 Java与Jni类型对应关系 2 String到char数组 具体使用方式 JNIEXPORT jstring JNICALL Java_com_zhoulee ...

  2. Java JNI初探

    ---说明,之前直接百度出来的例子,照猫画虎.没想到的是这例子居然直接来自百度百科,写着写着就囧了.. ---anyway,写完了就当是给自己看吧. 同事求助,就看了一下,照猫画虎一番,略有所得. J ...

  3. java初探native

    最近碰见一个java中一个native关键字,不知道是干什么的,如下: public native String FileName(String strURL);     static{        ...

  4. JVM初探- 内存分配、GC原理与垃圾收集器

    JVM初探- 内存分配.GC原理与垃圾收集器 标签 : JVM JVM内存的分配与回收大致可分为如下4个步骤: 何时分配 -> 怎样分配 -> 何时回收 -> 怎样回收. 除了在概念 ...

  5. Android开发学习之路--Android系统架构初探

    环境搭建好了,最简单的app也运行过了,那么app到底是怎么运行在手机上的,手机又到底怎么能运行这些应用,一堆的电子元器件最后可以运行这么美妙的界面,在此还是需要好好研究研究.这里从芯片及硬件模块-& ...

  6. Android之——JNI配置C语言打印Logcat信息

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/47425073 这篇文章给大家介绍一下在JNI中怎样为C语言配置打印Logcat信息 ...

  7. ffmpeg mediacodec 硬解初探

    ffmpeg mediacodec 硬解初探 1编译: ffmpeg自3.1版本加入了android mediacodec硬解支持,解码器如图 硬件加速器如图(还不清楚硬件加速器的功能) 编译带h26 ...

  8. android studio 使用 jni 编译 opencv 完整实例 之 图像边缘检测!从此在andrid中自由使用 图像匹配、识别、检测

    目录: 1,过程感慨: 2,运行环境: 3,准备工作: 4,编译 .so 5,遇到的关键问题及其解决方法 6,实现效果截图. (原创:转载声明出处:http://www.cnblogs.com/lin ...

  9. 【走过巨坑】android studio对于jni调用及运行闪退无法加载库的问题解决方案

    相信很多小伙伴都在android开发中遇到调用jni的各种巨坑,因为我们不得不在很多地方用到第三方库so文件,然而第三方官方通常都只会给出ADT环境下的集成方式,而谷歌亲儿子android studi ...

随机推荐

  1. 基因探针富集分析(GSEA)& GO & pathway

    http://blog.sina.com.cn/s/blog_4c1f21000100utyx.html GO是Gene Ontology的简称,是生物学家为了衡量基因的功能而而发起的一个项目,从分子 ...

  2. 阿里云服务器windows系统C盘一键清理脚本

    @ECHO OFF @echo @echo @echo 清理几个比较多垃圾文件的地方 DEL /F /S /Q "C:\WINDOWS\PCHealth\ERRORREP\QSIGNOFF\ ...

  3. spring mvc 资源包的映射

    在springmvc.xml中进行设置: <?xml version="1.0" encoding="UTF-8"?> <beans xmln ...

  4. 关于Visual Studio未能加载各种Package包的解决

    参考微软社区的一个答复解决了VS2013的问题: 进入VS对应的用户缓存文件夹,删掉那个Microsoft.VisualStudio.Default.cache缓存文件,就可以了. 这个错误估计是我们 ...

  5. [随笔]利用云虚拟机和学校VPN实现校外访问校内站点(反向代理)

    探究背景简介: 大学校内站点一般不对外开放,个人认为原因有二: 一是站点内容受众就是大学师生: 二是站点基本无防御措施,在公网环境下容易发生意外情况. 至于为何不对外开放,不是这篇随笔探讨的重点,利用 ...

  6. android:在ViewPager中使用Button

    最近在项目用用到ViewPager ,其中页面包含有Button,因为之前也有使用个ViewPager ,所以这个也照搬之前的方式,测试后发现点击button无法执行,这个button是在第一页面的默 ...

  7. JS与浏览器的几个兼容性问题

    第一个:有的浏览器不支持getElementsByClassName(),所以需要写一个function()来得到需要标签的class,然后进行class的增加.删除等操作. 第二个:在需要得到特定标 ...

  8. Qt入门之基础篇 ( 二 ) :Qt项目建立、编译、运行和发布过程解析

    转载请注明出处:CN_Simo. 题解: 本篇内容主讲Qt应用从创建到发布的整个过程,旨在帮助读者能够快速走进Qt的世界. 本来计划是讲解Qt源码静态编译,如此的话读者可能并不能清楚地知道为何要静态编 ...

  9. ADO.NET 扩展属性、配置文件 和 对战游戏

    扩展属性 有外键关系时将信息处理成用户可看懂的 利用扩展属性 如:Info表中的民族列显示的是民族代号处理成Nation表中的民族名称 需要在Info类里面扩展一个显示nation名称的属性 例:先前 ...

  10. 蓝桥网试题 java 基础练习 数列特征

    ----------------------------------- Collections.sort(list);是个好东西 但是要学会排列 然后你才能浪 -------------------- ...