Linux下JNI调用简单实例操作全过程

简介:
开发环境:Linux(Ubuntu 11.04) + JDK 7
实例说明:利用JNI调用本地代码的方法来实现一个计算Int数组总和的功能


使用JNI调用本地代码,整个开发流程主要包括以下几个步骤:
1、创建一个Java类(IntArray.java);
2、使用javac编译该类(生成IntArray.class);
3、使用javah -jni 产生头文件(生成IntArray.h);
4、使用本地代码实现头文件中定义的方法(编写IntArray.c);
5、编译生成本地动态库(生成libIntArray.so);
6、使用Java运行程序。


一、创建一个Java类(IntArray.java)
class IntArray{
	private native int sumArray(int[] arr);
	public static void main(String[]args){
		IntArray p = new IntArray();
		int arr[] = new int[10];
		for(int i =0;i<10;i++){
			arr[i] = i;
		}

		int sum = p.sumArray(arr);
		System.out.println("Sum = "+sum);
	}

	static{
		System.loadLibrary("IntArray");
		}
}
注:
     1、在Java代码中声明本地方法必须有"native"标识符,native修饰的方法,在Java代码中只作为声明存在。例如: private native int sumArray(int[] arr);
     2、在调用本地方法前,必须首先装载含有该方法的本地库. 如IntArray.java中所示,置于static块中,在Java VM初始化一个类时,首先执行这部分代码,这可保证调用本地方法前,装载了本地库。
	static{
		System.loadLibrary("IntArray");
		}


二、使用javac编译该类(生成IntArray.class)
javac IntArray.java

三、使用javah -jni 产生头文件(生成IntArray.h)
javah -jni IntArray

生成IntArray.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class IntArray */

#ifndef _Included_IntArray
#define _Included_IntArray
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     IntArray
 * Method:    sumArray
 * Signature: ([I)I
 */
JNIEXPORT jint JNICALL Java_IntArray_sumArray
  (JNIEnv *, jobject, jintArray);

#ifdef __cplusplus
}
#endif
#endif


四、使用本地代码实现头文件中定义的方法(编写IntArray.c)
复制IntArray.h成IntArray.c,对于IntArray.c做以下修改:
1、添加头文件:#include "IntArray.h"
2、去掉以下几句
#ifndef _Included_IntArray
#define _Included_IntArray
#endif
3、实现头文件中定义的方法

IntArray.c具体代码如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class IntArray */
#include "IntArray.h"

#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     IntArray
 * Method:    sumArray
 * Signature: ([I)I
 */
JNIEXPORT jint JNICALL Java_IntArray_sumArray
  (JNIEnv *env, jobject obj, jintArray arr)
{
	jint buf[10] ={0};
	jint i = 0,sum = 0;
	
	(*env)->GetIntArrayRegion(env,arr,0,10,buf);
	
	for(i=0;i<10;i++)
	{
		sum += buf[i];
	}
	
	return sum;
}
#ifdef __cplusplus
}
#endif


五、编译生成本地动态库(生成libIntArray.so)
根据本地代码(IntArray.h,IntArray.c)生成本地动态库,命令如下:
gcc -I/usr/lib/jvm/java-7-sun/include/ -I/usr/lib/jvm/java-7-sun/include/linux/ -fPIC -shared -o libIntArray.so IntArray.c
注:
其中 -I后面是java的include文件夹地址,请根据您具体的java版本以及安装路径作相应改变;
-f后面的PIC表示生成的库中符号是与位置无关的(PIC就是Position Independent Code),关于PIC,可以参考这篇文章
<a href="http://www.gentoo.org/proj/en/hardened/pic-guide.xml">Introduction to Position Independent Code</a>  
-shared表示共享,共享库后缀名.so可以认为是shared object的简称;
-o libIntArray.so,可以理解为编译后输出libIntArray.so库。

六、使用Java运行程序
java IntArray 

可能出现以下结果:
snowdream@snowdream:~$ java IntArray 
Exception in thread "main" java.lang.UnsatisfiedLinkError: no IntArray in java.library.path
	at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
	at java.lang.Runtime.loadLibrary0(Runtime.java:845)
	at java.lang.System.loadLibrary(System.java:1084)
	at IntArray.<clinit>(IntArray.java:15)

分析异常提示可知,我们之前生成的共享库不在系统默认的共享库路径中,程序找不到共享库报错。
解决方法有两个:
1、临时指定共享库libIntArray.so的路径。
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
注:该方法只在当前会话窗口有效,切换到另外一个终端窗口,则需要重新指定共享库路径。

2、运行时加上参数指定共享库libIntArray.so的路径。
java -Djava.library.path=.  IntArray
注:-D:设置Java平台的系统属性。 此时JavaVM可以在当前位置找到该库。

通过以上任意方法,您都可以得到正确的运行结果:
snowdream@snowdream:~$ java IntArray 
Sum = 45

相关文章
|
20天前
|
存储 安全 数据管理
探索Linux的挂载操作🌈
在Linux这个强大的操作系统中,挂载操作是一个基本而重要的概念。它涉及到文件系统、设备和数据访问,对于理解Linux的工作方式至关重要。那么,挂载操作究竟是什么,为什么我们需要它,如果没有它,我们将面临什么问题呢?让我们一起深入探讨。
探索Linux的挂载操作🌈
|
29天前
|
Linux Windows
Linux之基本指令操作
Linux之基本指令操作
|
1月前
|
Linux C语言
Linux系统下C语言的队列操作
Linux系统下C语言的队列操作
23 0
|
1月前
|
Linux 开发工具 git
Linux嵌入式系统中如何使用U-Boot实例
Linux嵌入式系统中如何使用U-Boot实例
26 0
|
1月前
|
Linux
嵌入式linux系统设备树实例分析
嵌入式linux系统设备树实例分析
39 0
|
2月前
|
存储 Linux API
Linux应用开发基础知识——文件IO操作(三)
Linux应用开发基础知识——文件IO操作(三)
54 2
Linux应用开发基础知识——文件IO操作(三)
|
1月前
|
存储 算法 Shell
【Shell 命令集合 磁盘维护 】Linux 对软盘进行格式化操作 fdformat命令使用指南
【Shell 命令集合 磁盘维护 】Linux 对软盘进行格式化操作 fdformat命令使用指南
32 0
|
1月前
|
Shell Linux C语言
【Shell 命令集合 磁盘管理 】Linux 控制光驱或可移动媒体设备的弹出和关闭操作 eject命令使用教程
【Shell 命令集合 磁盘管理 】Linux 控制光驱或可移动媒体设备的弹出和关闭操作 eject命令使用教程
36 1
|
1天前
|
Ubuntu Linux
Linux(Ubuntu)系统临时IP以及静态IP配置(关闭、启动网卡等操作)
请注意,以上步骤是在临时基础上进行配置的。如果要永久保存静态IP地址,通常还需要修改 `/etc/network/interfaces`文件,以便在系统重启后保持配置。同时,确保备份相关配置文件以防止出现问题。
12 1
|
3天前
|
Ubuntu Linux 数据安全/隐私保护
Linux(24) 如何在Ubuntu中操作rootfs.img文件
Linux(24) 如何在Ubuntu中操作rootfs.img文件
9 0