JNI——手工编译HelloJNI
原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处、作者信息和本声明。否则将追究法律责任。http://blog.csdn.net/taotaoyouarebaby/article/details/8747580 |
介绍
JVM封装了各种操作系统实际的差异性的同时,提供了JNI技术,它是一种双向的接口,使得开发者可以通过Java代码调用到各种native的 库,反之亦然。所以JNI(Java Native Interface)能作为Java语言的一部分,她能够作为粘合剂将Java应用和其他本地应用(C/C++,Delphi)集合在一起.
下图就很好的描述了JNI在Java应用中的地位和角色:
作为一个双向的接口,JNI能支持两种native代码:native libraries 和native applications.
(1)你能使用JNI去写一些native methods去允许Java Applications能呼叫native libraries中的函数,native methods的具体实现是可能C,C++或者Delphi
(2)JNI也支持嵌入一个JVM实现到一个本地应用程序中去,去执行那些用Java语言编写的的模块.比如,一个C++编写的浏览器利用内嵌的JVM去执行下载到本地的applet.
实现”JNI-Java invoke Native Library”的一般步骤如下:
1) 完成Java代码,编写好Java调用类
2)编译你的Java类
3)用javah生成编译好的class文件对应的C/C++ 函数的头文件
4) 实现头文件中的函数原型,编写native代码
5) 将native代码编译打包成DLL库(win32)或共享库(Linux)
6)将你的Java代码跑起来
手工编译HelloJNI
环境与工具:
win7 x64
jdk1.7.0
vs 2012 compiler for x64
当前目录:E:\programming\practice\java\JNI
编写java代码
//HelloJNI.java
package edu.zt.jni; public class HelloJNI { public native void sayHello(); public static void main(String[] args) { System.loadLibrary("hellojni"); new HelloJNI().sayHello(); } } |
编译HelloJNI.java
javac -d . HelloJNI.java |
导出C/C++函数头文件
javah edu.zt.jni.HelloJNI |
得到edu_zt_jni_HelloJNI.h
#include <jni.h> #ifndef _Included_edu_zt_jni_HelloJNI #define _Included_edu_zt_jni_HelloJNI #ifdef __cplusplus extern "C" { #endif JNIEXPORT void JNICALL Java_edu_zt_jni_HelloJNI_sayHello (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif |
注意到上面的头文件中包含了一个外部头文件jni.h,该头文件可以从%jdk%\include\中找到。但是在jni.h中还包含了jni_md.h文件,此文件位于%jdk%\include\win32中。
于是将jni.h和jni_md.h文件复制到当前目录,并将edu_zt_jni_HelloJNI.h文件中的
#include <jni.h> 改为 #include “jni.h” |
编写native代码
//HelloJNI.c
#include <stdio.h> #include "edu_scu_jni_HelloJNI.h" JNIEXPORT void JNICALL Java_edu_scu_jni_HelloJNI_sayHello(JNIEnv * env, jobject obj) { printf("Hello JNI!"); } |
编译native代码为DLL库
因为本机使用的是64位的java VM,所以需要编译为64位的程序,因为也就需要为64位程序设计的编译器。在此,我使用vs2012的64位编译器进行编译。
找到:开始菜单->Microsoft Visual Studio 2012->Visual studio tools->VS2012 x64 Cross Tools Command Prompt。点击即可打开为编译64位程序配置好的命令行(主要是设置了一些PATH和LIB)。
该命令行具体配置了什么内容可以查看vcvarsall.bat文件。
查看VS2012 x64 Cross Tools Command Prompt快捷方式的属性,目标位置有以下内容:
%comspec% /k ""D:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"" x86_amd64 |
转到当前工作目录,编译HelloJNI
cl /c HelloJNI.c |
此外要生成DLL文件还需要一个.def文件。
//hellojni.def
LIBRARY HelloJNI EXPORTS Java_edu_scu_jni_HelloJNI_sayHello @1 |
连接HelloJNI生成DLL
link /def:HelloJNI.def /dll HelloJNI.obj |
可能会出现如下警告
warning LNK4197: export xx specified multiple times; using first specification |
但无关紧要。
至此hellojni.dll文件成功生成!
运行
java edu.zt.jni.HelloJNI |
出现
Hello JNI! |
至此方为成功!
JNI的优缺点
JNI 编程在软件开发中运用广泛,其优势可以归结为以下几点:
1 利用 native code 的平台相关性,在平台相关的编程中彰显优势。
2 对 native code 的代码重用。
3 native code 底层操作,更加高效。
然而任何事物都具有两面性,JNI 编程也同样如此。程序员在使用 JNI 时应当认识到 JNI 编程中如下的几点弊端,扬长避短,才可以写出更加完善、高性能的代码:
1 从 Java 环境到 native code 的上下文切换耗时、低效。
2 JNI 编程,如果操作不当,可能引起 Java 虚拟机的崩溃。
3 JNI 编程,如果操作不当,可能引起内存泄漏。
4 使应用失去了跨平台的能力,如果要移植到别的平台就需要重写native代码。
附
HelloJNI文件列表
参考
http://blog.csdn.net/todototry/article/details/1638849 如何手工编写动态链接库(windows dll)
http://blog.csdn.net/ididcan/article/details/6828982 JNI简单实现Java调用C++/C的HelloWorld
传智播客_王择佑_JNI第一讲
http://www.ibm.com/developerworks/cn/java/j-lo-jnileak/index.html?ca=drs- 在 JNI 编程中避免内存泄漏
问题:
jni.h的实现文件(dll库)在哪里,这个我还没有整明白。