前言 :
JNI(Java Native Interface)提供了一种操作,可以在程序局部使用其他语言(C/C++)来替代Java,从而达到提升代码执行效率的效果,本篇以HelloWorld为例,具体介绍在Ubuntu 16.04 +JDK9.0.4的环境下如何使用JNI实现在Java内部采用C语言构造HelloWorld,使用java 命令执行程序输出HelloWorld。
第一步 : 编写 HelloJNI.java
//package hello; //if you use IDE,please comment out it
public class HelloJNI {
static {
//System.loadLibrary("Hello");//use this may cause some problem
System.load("/usr/java/packages/lib/Hello.so");//add your .so path
}
private native void sayHello();
public static void main(String[] args) {
new HelloJNI().sayHello();
}
}
其中System.load用于载入动态库,上述的Hello.so将在后面使用gcc生成。
使用javac编译生成.class
>javac HelloJNI.java
第二步 : 生成 HelloJNI.h
如果你的JDK版本低于8,使用:
>javah HelloJNI
若JDK版本高于8.使用:
>javac -h . HelloJNI.java
note : -h 后面接一个 “.” 代表在当前目录
生成的HelloJNI.h如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class hello_HelloJNI */
#ifndef _Included_hello_HelloJNI
#define _Included_hello_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: hello_HelloJNI
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_hello_HelloJNI_sayHello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
至于上述.h的具体意义可参考文末的参考资料
第三步 : 编写HelloJNI.c
#include <jni.h>
#include <stdio.h>
#include "HelloJNI.h"
// Implementation of native method sayHello() of HelloJNI class
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) {
printf("Hello World!\n");
return;
}
可以看出HelloJNI.c 实际上是HelloJNI.java中的:
new HelloJNI().sayHello();
实例化的对象,而该对象采用的是C语言来描述的。
生成.so动态链接库,使用命令:
>gcc -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" -fPIC -shared -o Hello.so HelloJNI.c
参考:https://stackoverflow.com/questions/13466777/jni-h-no-such-file-or-directory
note :
1 : -I 命令前面接java命令所在的目录;后面接native language所在的目录。
2 : -fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
生成的Hello.so即可在HelloJNI.java的:
System.load("/usr/java/packages/lib/Hello.so");
载入到java.library
第五步 : 运行HelloJNI.java
使用命令:
>java HelloJNI
即可输出:
XXX-All-Series:~/eclipse-workspace/hello/src/hello$ java HelloJNI Hello World!
后记 :
之所以不使用:
System.loadLibrary("Hello");
在使用该句时,程序会抛出异常:
java HelloJNI Exception in thread "main" java.lang.UnsatisfiedLinkError: no Hello in java.library.path
该异常表示在java.library.path中未找到名为Hello的动态库
使用命令:
>java -XshowSettings:properties
在其输出中找到java.library.path
我的path如下:
>java.library.path = /usr/java/packages/lib /usr/lib64 /lib64 /lib /usr/lib
1 : 采用网上所用的一些奇技淫巧修改java.library.path;
2 : 使用命令:
>java -Djava.library.path=. HelloJNI
3 : 将Hello.so放入系统所述的java.library.path目录下;
上述操作都没有什么D用,依然抛出相同的异常。
在使用命令:
>System.load("/usr/java/packages/lib/Hello.so");
之后,一切正常。
主要参考 :
https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html
PS:( 如若侵权请联系本人删除,谢)
网友评论