背景
JNI 全称是Java Native Interface ,用来实现java对c/c++等编译方法的调用。常见如Jdk Object Thread
等类中也有许多基于jni的Native方法,还有一些与硬件、操作系统直接交互或者为了提高执行性能而使用jni调用。
说明
本期介绍一个使用jni示例,用java调用c++生成的链接库,实际执行c++实现的方法。大致步骤如下:
- 定义java native方法;
- 编译java得到class字节码;
- 生成jni链接使用的c/c++头文件;
- 编写c/c++代码实现;
- 生成链接库;
- 配置java执行链接库地址;
- 执行jni实现示例;
代码
生成java代码和编译
注意这里笔者本地根目录是/export/code/java
,且这里额外创建了package
#cd /export/code/java
#mkdir -p com/test
编写Java代码
//NativeTest.java
package com.test;
public class NativeTest {
//定义方法
public final native void sayHello();
//注意名字对应结果库 libxxx.so,否则找不对
static {
System.loadLibrary("echoHello");
}
//调用结果
public static void main(String[] args){
NativeTest test = new NativeTest();
test.sayHello();
}
}
注意
loadLibrary
加载的名称要对应libxxx.so的xxx部分
生成class字节码
#javac com/test/NativeTest.java
javah 生成头文件
当前目录在/export/code/java
#javah com.test.NativeTest
生成头文件如下, com_test_NativeTest.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_test_NativeTest */
#ifndef _Included_com_test_NativeTest
#define _Included_com_test_NativeTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_test_NativeTest
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_test_NativeTest_sayHello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
编写c++代码
这部分用来编写c++代码,具体实现我们在java中定义的native方法。当前目录在/export/code/java
//EchoHello.cpp
#include "jni.h"
#include "com_test_NativeTest.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_com_test_NativeTest_sayHello(JNIEnv *env, jobject obj){
//执行的结果
printf("hello , my hello !\n");
return;
}
int main(){
return 0;
}
编译c++代码,生成链接库
使用命令将cpp编译,生成链接库so文件。
#g++ -fPIC -I /export/usr/jdk/jdk1.8.0_201/include/ -I /export/usr/jdk/jdk1.8.0_201/include/linux/ -shared EchoHello.cpp -o libechoHello.so
注意:1. 需要根据环境配置使用 -I 参数引入对应的依赖,比如笔者本地ubuntu 使用 /include/linux 。 2. 注意这里链接库的命名。
关于PIC参数解释:fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。[2]
运行结果
将当前目录添加到链接库地址
这是必须的一步,将本地生成的链接库文件添加到java执行环境中才能使用。(以下命令运行在*nix环境)
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/export/code/java
结果展示
my@localhost:/export/code/java$ java com.test.NativeTest
hello , my hello !
my@localhost:/export/code/java$
参考链接
可能由于未知因素影响,部分链接会失效
网友评论