背景知识

本地代码

在JAVA中使用其他语言的代码(如C/C++)称为本地代码。

历史原因

JAVA的早期阶段,很多人认为使用C和C++来加速JAVA应用中的关键部分是个好主意,但是实际上,虽然JAVA的代码确实没有纯C的运行快,但是JAVA平台实现要更快,也更稳定。

本地代码的应用场景

本地代码,比如C,对于跨平台需求,需要针对支持的平台提供单独的本地类库,而且使用C/C++编写的代码没有对通过使用无效指针所造成的内存腹泻提供任何包含,比如内存回收等,所以会容易破坏程序。因此,只有在必要的时候才使用本地代码,如下三种场景:

  1. 应用需要访问的系统特性和设备通过JAVA平台无法实现。
  2. 已经有了大量的测试过和调试过的用另一种语言编写的代码,比如图像算法,并且知道如何将其导出到所有的目标平台上。
  3. 通过基准测试,编写的JAVA代码比其他语言编写的等价代码要慢。

JNI

JNI是Java Native Interface的缩写,JNI是JAVA平台专门用于和本地C代码进行相互操作的API,称为JAVA本地接口。

JNI开发流程

  1. 在JAVA中先声明一个native方法。
  2. 通过javac -h或javah -jni命令导出JNI使用的C头头文件。
  3. 使用C实现本地方法。
  4. 将本地代码变异成动态库,windows下是.dll文件,linux下是.so文件。
  5. 在JAVA程序中加载步骤4中生成的类库,执行JAVA程序,最终实现JAVA本地代码。

JNI头文件规则

在JAVA中,调用本地代码,需要实现本地代码,需要编写一个相应的C函数,而C函数需要按照JAVA虚拟机的规则来实现,其规则如下:

  1. 使用完成的JAVA方法名,比如上例中,HelloNative.greeting,如果该类属于某个包,还需要在前面添加包名称,比如com.horstmann.HelloNative.greeting.
  2. 用下划线’_‘替换掉1中的所有’.’,然后添加上Java_前缀,比如:Java_HelloNative_greeting或
    Java_com_horstmann_HelloNative_greeting
  3. 如果类名中含有非ASCII字母或数字,如’_’,’$‘或大于’\u007F’的Unicode字符,用_0xxxx来替代,xxxx是该字符的Unicode值的4个十六进制数序列。
    示例
    本例中,通过简单的打印功能C函数来举例,在C中使用printf来实现某个打印函数,在JAVA中调用该功能函数。

1. 使用native创建一个本地方法。

JAVA中使用关键字native表示本地方法,在JAVA类中声明一个方法,我们先创建一个HelloNative类,代码如下:

public class HelloNative {public static native void greeting();
}

2. 使用javac -h生成头文件

使用 -h 标志运行javac (java 编译工具),提供头文件存放目录,实现对应头文件的生成。命令代码如下:

javac -h ./ HelloNative.java

运行上述命令后,就会在./ (当前目录)下自动生成一个名为 HelloNative.h的头文件,头文件内容如下:

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

其中JNIEXPORT和JNICALL为宏定义,在头文件jni.h中定义,jni.h在JDK安装包中已经包含。他们的作用是为自动装在库的导出函数表明了依赖于编译器的说明符。

3. 编写本地方法的C代码

我们需要根据头文件中本地方法的声明原型,使用C实现,程序如下:

#include <stdio.h>
#include "HelloNative.h"JNIEXPORT void JNICALL Java_HelloNative_greeting(JNIEnv *env, jclass cl)
{printf("this is hello native .c printf\n");
}

上述代码中,include了步骤2生成的头文件,另外补充了JNIEnv和jclass,默认的参数。

4. 在linux下,编写该C代码的动态库

需要说明的是,由于该C代码引用了jdk中的 jni.h头文件,所以生成动态库时,需要引用JDK的头文件位置,命令码如下:

gcc -fPIC -I/opt/ctools/jdk1.8.0_301/include/ -I/opt/ctools/jdk1.8.0_301/include/linux/ -shared -o libHelloNative.so HelloNative.c

其中/opt/ctools/jdk1.8.0_301/include/ 和 /opt/ctools/jdk1.8.0_301/include/linux为依赖jdk的头文件目录。
编译生成了 libHelloNative.so 共享库。

5. 在JAVA程序中加载步骤5中生成的类库,执行

在JAVA程序中,通过System.loadLibrary方法调用动态库,我们再编写一个HelloNativeTest测试类,代码如下:

public class HelloNativeTest {public static void main(String[] args){HelloNative.greeting();}static{System.loadLibrary("HelloNative");}}

使用javac 编译该测试类

javac HelloNativeTest.java

将步骤4中生成的动态库添加到库路径中,命令如下:

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

编译生成HelloNativeTest.class 字节码, 使用java命令执行

java HelloNativeTest

执行命令结果如下:

this is hello native .c printf

至此就实现了在JAVA中调用C本地代码的完整示例。

JAVA中调用C语言函数简单教程相关推荐

  1. java中调用c_java中调用c语言函数?

    拉丁的传说 要在java中调用c语言的库,需要使用Java提供了JNI.举例说明在c语言中定义一个 void sayHello()函数(打印Hello World);然后在Java中调用这个函数显示H ...

  2. java 中调用 Matlab 的函数

    一.matlab版本必须支持java 在command 模式下面运行deploytool,如果支持该命令即可使用 二.matlab中function的书写 %定义一个函数operation(a,b), ...

  3. c#调用c语言的自定义函数,[转]在C#中调用C语言函数(静态调用Native DLL,Windows Microsoft.Net平台)...

    对于不太了解.Net的人,如果想要了解.Net,我必须给他介绍P/Invoke.P/Invoke是什么呢?简单地说,就是在.Net中调用本地代码(Native code)的一种解决方案.所谓" ...

  4. Linux X64下汇编学习:C语言调用汇编代码,汇编中调用C语言函数

    Table of Contents hello world hello.asm makefile float circle_fpu_87c.c circle_fpu_87.asm makefile s ...

  5. 如何将matlab代码转为C语言(2)--在C++中调用matlab的函数

    如何将matlab代码转为C语言(2)–在C++中调用matlab的函数 在上一条博文中提供了一种直接在matlab操作中的方法,下面提供一种新的调用方法,即在C++中调用matlab中的dll文件. ...

  6. f2py支持在fortran语言中调用其他Fortran函数或C代码或Python代码

    f2py支持在fortran语言中调用其他Fortran函数或C代码或Python代码 分类: Python Numpy_Scipy fortran MinGW_GCC_Boost f2py 2012 ...

  7. java 调用matlab函数_java中调用Matlab的函数+注意事项

    一.matlab版本必须支持java 在command 模式下面运行deploytool,如果支持该命令即可使用 二.matlab中function的书写 %定义一个函数operation(a,b), ...

  8. Matlab函数打包为.jar后在java中调用出现错误:Exception:com.mathworks.toolbox.javabuilder.MWException: An error occur

    Matlab函数打包为.jar后在java中调用出现错误:Exception:com.mathworks.toolbox.javabuilder.MWException: An error occur ...

  9. java中调用python

    在Java中调用Python </h1><div class="clear"></div><div class="postBod ...

最新文章

  1. “分布式哈希”和“一致性哈希”的概念与算法实现
  2. 转:中国互联网十五年的22个创新模式
  3. 二维字符数组按长度排序_字符串长度 字符数组长度
  4. android 设置键盘弹出动画,Android实现键盘弹出界面上移的实现思路
  5. 【Linux】一步一步学Linux——enable命令(212)
  6. python中函数的可变参数解析
  7. maven常用插件功能
  8. java websphere mq_如何在java中使用WebSphere MQ?
  9. 我的博客园css样式
  10. cp 强制覆盖_Office 365办公本组CP,软硬件同步提高效率
  11. php获取当地时间 time zone
  12. 请各位程序员 正在创业的 正在努力赚钱的 好好看看下面的话
  13. nuxt vue ssr实现
  14. 计算机专业中专自我鉴定范文,计算机专业中专生自我鉴定范文
  15. 账户验证业务规则及改造要点介绍
  16. 腾讯地图产业版WeMap 升级
  17. 【PCL】PCL点云库介绍及VS环境配置
  18. Event Handing guide for iOS
  19. 一代王者回归?滴滴暂停563天,恢复新用户下载,江湖格局又生变
  20. Vue3 Echarts散点图+高德地图+卫星地图(一)——获取高德地图API

热门文章

  1. Andorid App程序启动流程
  2. 刘海屏启动页全屏适配
  3. 自组织神经网络SOM——MATLAB
  4. 视频教程-全套Photoshop教程+20个基础技巧课程+海报排版案例(入门版)-Photoshop
  5. 永磁同步电机矢量控制(四)——速度环 PI 参数整定(四)
  6. c语言 函数参数 const,c语言中const的使用方法
  7. 【LeetCode 剑指 Offer 65】不用加减乘除做加法
  8. 2023最新稳定的礼品单号代发网系统源码,一键自动发货、api、无线分站、数据统计、自建仓、云仓全部包含
  9. Python爬虫Requests库入门及HTTP协议
  10. 百度地图android HD版,百度地图hd版Android版