【0】README

1) 本文部分文字描述 转自 core java volume 2 , 旨在理解 本地方法——从java 程序中调用C函数 的基础知识 ;
2) for source code, please visit https://github.com/pacosonTang/core-java-volume/tree/master/coreJavaAdvanced/chapter12/javaCassFuncOfC

【1】本地方法相关

1)本地代码定义: 原则上说, 100% 纯 java 的解决方案是非常好的, 但有时你也会想要编写或使用其他语言的代码, 这种代码就称为本地代码;
2)我们建议只有在必需的时候才使用本地代码, 特别是在以下三种情况的时候(cases):

  • c1)你的应用需要访问的系统特性和设备通过java 平台无法实现;
  • c2)你已经有了大量的测试过 和 调试过的 用另一种语言编写的代码, 并且知道如何将其导出到所有的目标平台上;
  • c3)通过基准测试, 你发现所编写的 java 代码比用另一种语言编写的等价代码要慢很多;

3)java 本地接口(JNI): java 平台有一个用于和本地C 代码进行交互操作的 API, 称为java 本地接口(JNI);


【2】从java 程序中调用C函数

1) 关键字native: java 使用 native 表示本地方法;

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

2)本地方法: 既可以是静态的,也可以是非静态的;
3)为了实现本地代码: 需要编写一个C 函数,你必须完全按照 java 虚拟机预期的那样来命名这个函数。 其规则是(rules):

  • r1)使用完整的java 方法名:

    如 HelloNative.greeting; 如果属于某个包还要添加包名, 如 com.corejava.HelloNative.greeting;

  • r2)用下划线替换掉所有的句号, 并加上 Java_前缀, 如:

    Java_com_corejava_HelloNative_greeting;

  • r3)如果类名含有非 ASCII 字母或数字:

    如:’_’, ‘$’ 或是 大于 ‘\u007F’ 的 unicode 字符,用_0xxxx 来替代它们, xxxx 是该字符的unicode 值的 4个十六进制数序列;

Attention)

  • A1)如果你重载本地方法, 也就是说, 你用相同的名字提供多个本地方法, 那么你必须在名称后面附加两个下划线, 后面再加上已编码的参数类型;
  • A2) 看个荔枝: 如果你有一个本地方法 greeting 和 本地方法 greeting(int repeat), 那么第一个称为 Java_HelloNative_greeting__, 第二个称为 Java_HelloNative_greeting_I;
  • A3)javah程序:没有人完成这些手工操作, javah 自动生成函数名;

4)java程序调用C函数的实现steps:

  • (javah导出类的头文件可能抛出异常——java.lang.IllegalArgumentException: Not a valid class name, for solution, please visit http://blog.csdn.net/pacosonswjtu/article/details/50615988)

  • step1)用 javah 生成函数名:

  • 对以上代码的分析(Analysis):

    • A1) 这个头文件包含了函数 Java_HelloNative_greeting 的声明;
    • A2) 字符串 JNIEXPORT 和 JNICALL 是在头文件 jni.h 中定义的, 他们为那些来自动态装载库的导出函数标明了 依赖于编译器的说明符;
  • step2)现在,需要将 函数原型从头文件中 复制到源文件中, 并且给出函数的实现代码(新建 HelloNative.c);

  • step3) 将本地C 代码编译到一个动态装载库中, 具体方法依赖于编译器;

    • step3.1) Linux 下的 GNU C 编译器:

      使用如下命令:(1) gcc -fPIC -I jdk/include -I jdk/include/linux -shared -o libHelloNative.so HelloNative.c 或
      (2.1) gcc -c -I /usr/java/jdk1.7/include/ -I /usr/java/jdk1.7/include/linux/ HelloNative.c
      (2.2) gcc -shared -fPIC -o HelloNative.so HelloNative.o

    • step3.2)使用windows 下的微软编译器:

      命令是: cl -I jdk/include -I >jdk/include/win32 -LD HelloNative.c -FeHelloNative.dll

    • step3.3)通过cygwin 环境下 将本地C 代码编译到动态装载库中:

      gcc -mno-cygwin -D __int64=”long long” -I jdk/include/win32 -shared -Wl, –add-stdcall-alias -o HelloNative.dll HelloNative.c

  • step4) 最后,我们要在程序中添加 一个对 System.loadLibrary 方法的调用。为了确保虚拟机第一次使用该类之前就会装载这个库, 需要使用 静态初始化代码块。 如下所示:

Attention)如果运行在 Linux 下, 必须把当前目录添加到库路径中。

  • A1)实现的方式可以是通过设置 LD_LIBRARY_PATH 环境变量:

    export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

  • A2)或者是设置 java.library.path 系统属性:

    java -Djava.library.path=. HelloNativeTest

Conclusion) 总之,遵循下面的steps就可以将一个本地方法链接到 java 程序中:

  • step1)在 java类中声明一个本地方法;

    package com.corejava.chapter12;public class HelloNative
    {  public static native void greeting();
    }
    
  • step2) 运行javah 以获得包含该方法的 C 声明的头文件;

  • step2.1)编译文件: javac com/corejava/chapter12/HelloNative.java

  • step2.2)javah生成该类的头文件: javah com.corejava.chapter12.HelloNative

step3) 用 C 实现该本地方法:

  • step3.1)将 相应的方法原型(返回类型,方法名,参数列表) copy 到 .c 文件中,并实现该方法):
#include "com_corejava_chapter12_HelloNative.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_com_corejava_chapter12_HelloNative_greeting(JNIEnv * env, jclass)
{printf("hello world ! this greeting is from native method by C");
}
  • step3.2)在linux环境下, 将本地C 代码编译到动态装载库中

    gcc -c -I /usr/java/jdk1.7/include/ -I /usr/java/jdk1.7/include/linux/ HelloNative.c
    gcc -shared -fPIC -o libHelloNative.so HelloNative.o

  • step4)将代码置于 共享类库中;

  • step5) 在 java 程序中 加载该类库(java类中的main调用C函数)

    • Warning) 这里运行可能出错,throw exception : java.lang.UnsatisfiedLinkError: no yourClassName in java.library.path , 这也就是 为什么本文先打印出了 java.library.path, 然后将 libHelloNative.so 添加到该共享库中的原因;当然了, for detailed spec , you can also refer to http://blog.csdn.net/pacosonswjtu/article/details/50618033

Conclusion) 最后的工作目录文件列表如下:

本地方法(JNI)——从java 程序中调用C函数相关推荐

  1. linux java 调用c_Linux上从Java程序中调用C函数

    原则上来说,"100%纯Java"的解决方法是最好的,但有些情况下必须使用本地方法.特别是在以下三种情况: 需要访问Java平台无法访问的系统特性和设备: 通过基准测试,发现Jav ...

  2. 如何在Java程序中调用Python算法脚本,重点讲Demo,不墨迹理论

    原创博文,欢迎转载,转载时请务必附上博文链接,感谢您的尊重. 前言 通过本篇,你将初步认识在Java程序中简单调用.py脚本文件的方法,附带入门的Demo实例讲解,更深入的理解还需要进一步学习. 最近 ...

  3. java程序中调用c语言库

    1.写一个调用的C程序的类 例如一个简单的字符串输入输出类: package com.lxy; public class TestC {static{System.loadLibrary(" ...

  4. insert时调用本身字段_「技术篇」ETL工具Kettle数据对比同步以及Java程序中调用

    作为一个技术栈出身的攻城狮,虽然走上管理之路,但是技术是不能扔下的,时不时的拿起来重温一下,理论与实践相结合... 使用背景: 住建部某区块链共享平台(下游系统)需要自于上游系统的生产库数据,数据量不 ...

  5. linux平台下通过mcr方式从c++程序中调用matlab函数

    小细节很多,所以容易出错. 平台:linux gcc matlab2010a 1 在matlab中写好函数例如branch,调用命令 mcc -W cpplib:libbranch -T link:l ...

  6. java arcengine_在Java程序中调用ArcEngine

    ArcEngine一般在C#中用的比较多,不过esri也是为Java提供了AE的类库的,不过文档确实没做的C#那么好.下面我记录一下如何在项目中配置使用AE的环境. 第一步:将arcobject.ja ...

  7. java主程序怎样调用子程序_存过和函数以及在Java程序中的调用

    存储过程,函数都是数据库的对象. 创建和调用 存储在数据库中的子程序,是由plsql语言写的,完成特定功能的程序. 函数可以返回值,存过不能返回值.除此之外,一致. create procedure ...

  8. 在Spark Scala/Java应用中调用Python脚本,会么?

    摘要:本文将介绍如何在 Spark scala 程序中调用 Python 脚本,Spark java程序调用的过程也大体相同. 本文分享自华为云社区<[Spark]如何在Spark Scala/ ...

  9. 教你如何在Spark Scala/Java应用中调用Python脚本

    摘要:本文将介绍如何在 Spark scala 程序中调用 Python 脚本,Spark java程序调用的过程也大体相同. 本文分享自华为云社区<[Spark]如何在Spark Scala/ ...

最新文章

  1. SAP MM采购定价过程的一个简单例子
  2. JAVA的JDBC连接数据库以及读取数据库数据
  3. python语法手册chm-python3.5.2官方帮助文档 参考手册(CHM版)
  4. 怎么查看地址值_西门子S7-200 SMART PID回路控制,配置PID向导,查看项目组件
  5. LeetCode 112路径总和-简单
  6. Just a Hook(线段树区间更新)
  7. 五个问答告诉你:阿里云对象存储如何助力钉钉战胜业务洪峰
  8. java写原生js_[Java教程]原生JS拖拽
  9. xps测试数据处理软件,XPS原始数据处理之 Avantage 软件篇
  10. 如何将Ubuntu中的chrome浏览器升级到最新版
  11. 【引用】pygame菜鸟入门指南
  12. 微信代码错误:40164,加入白名单仍不起作用。
  13. 【QT Creator学习记录】(一)上位机与下位机串口通信
  14. 自我激励的二十种方法
  15. Cox 比例风险模型中HR和置信区间
  16. 【TED笔记】如何掌控你的自由时间
  17. 这些00后的“火星文”你都认识吗?证明自己是小鲜肉的时刻终于到了
  18. 弘辽科技:抖音年货节推出新玩法。
  19. 利用opencv获取网络摄像头数据并显示报错 select() timeout
  20. 《大爱东方》今晚首播 “金话筒”何婕任主持人

热门文章

  1. Desert King POJ - 2728
  2. LIS最长上升子序列
  3. 牛客网【每日一题】5月22日 [CQOI2009]中位数图
  4. P4899-[IOI2018]werewolf 狼人【Kruskal重构树,主席树】
  5. jzoj4282-[NOIP2015模拟10.29B组]平方数游戏【构造】
  6. P3317-[SDOI2014]重建【矩阵树定理,数学期望】
  7. jzoj100046-收集卡片【暴力】
  8. codeforces1303 F. Number of Components(并查集+添_正序、删_逆序)
  9. 【模板】吉老师线段树
  10. 【矩阵乘法】【倍增】美食家(luogu 6772)