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
时间: 2024-10-24 08:24:52

Linux下JNI调用简单实例操作全过程的相关文章

Linux下TCP通信简单实例

基于TCP(面向连接)的socket编程,分为服务器端和客户端 服务器端的流程如下: (1)创建套接字(socket) (2)将套接字绑定到一个本地地址和端口上(bind) (3)将套接字设为监听模式,准备接收客户端请求(listen) (4)等待客户请求到来:当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept) (5)用返回的套接字和客户端进行通信(send/recv) (6)返回,等待另一个客户请求. (7)关闭套接字. 客户端的流程如下: (1)创建套接字(soc

关于webservice的异步调用简单实例

web|异步 关于webservice的异步调用简单实例无论在任何情况下,被调用方的代码无论是被异步调用还是同步调用的情况下,被调用方的代码都是一样的, 下面,我们就以异步调用一个webservice 为例作说明.这是一个webservice <WebMethod(Description:="试验")> _ Public Function delCurTable(ByVal tbName As String) As Boolean Try Return True Catch

并行计算-linux 下用p,V操作对两线程的操作

问题描述 linux 下用p,V操作对两线程的操作 计算/打印线程的同步:两个线程共享公共变量a线程1负责计算(+1)线程2负责打印 解决方案 我不太理解你问的问题的意图!公共变量a,在满足什么条件下,两线程的开始分配工作,你没有说清楚我假设你a==1时生产者工作,当a==2时,生产完成,线程2(即消费线程)开始工作即,打印a那么代码如下: #include <stdio.h>#include <stdlib.h>#include <pthread.h>pthread_

linux下java调用多行有相互依赖关系的shell命令,如何调用

问题描述 linux下java调用多行有相互依赖关系的shell命令,如何调用 小弟想用java调用用多行有前后依赖关系的shell命令: 例如: 先process=Runtime.getRuntime().exec("mysql");进入mysql命令行 在用java给mysq命令行传mysql脚本,执行脚本命令 麻烦大家回答一下,或者给点建议意见 解决方案 linux下java调用shell和windows下java调用bat 解决方案二: 通过管道重定向来接收和处理命令 解决方案

Linux下防火墙的简单配置与插入规则介绍_Linux

查看当前的防火墙设置 iptables -L INPUT -n --line-numbers 删除一条策略,例如第4行策略 iptables -D INPUT 4 -A:在尾部插入 -I (insert)在指定链中插入一条新规则,为指明插入到第几行 (如:在第七行插入) iptables -I INPUT 7 -p tcp -m state --state NEW -m tcp --dport 81 -j ACCEPT 然后保存 service iptables save 然后重启 servic

HTML页面,测试JS对C函数的调用简单实例_javascript技巧

这里记一下,以后要用的时候可以查! <HTML> <HEAD> <META NAME="GENERATOR" Content="Microsoft Visual Studio"> <meta http-equiv="content-type" content="text/html;charset=gbk"> <TITLE>HTML页面,测试JS对C函数的调用</

Linux下vi替换字符命令操作实例

http://blog.csdn.net/zhouzhaoxiong1227/article/details/28657665 在Linux下的开发中,经常涉及到对文件中的字符进行处理,其中,对字符的替换操作也是非常的频繁.         本文以一个实际的文件为例,详细介绍了Linux下常用的vi替换字符命令,为相关的开发工作提供给了参考.           本文中被操作的文件为TestFile.txt,其中的内容如下:         zhou@linux:~/zhouzx/Test> c

Linux下C编程-----IO/文件操作/内存映射 实现简单记录存储(3)

利用linux下的文件内存映射可以实现进程共享数据,我们可以把一个文件映射到虚拟内存中使多个进程进行共享, 到这里我们大概能想到他能应用到的领域 是很广泛的  主要涉及到 mmap  munmap   msync 三个函数的应用 下面贴代码  下面一段代码是为文件建立一个简单的记录存储,并且通过内存映射修改文件内容 /************************************************************************* > File Name: mem

Linux下C编程-----IO/文件操作 模拟linux ls程序显示文件系统树形结构(2)

Linux下的IO/文件操作练习,知识虽然简单 但是往往基础容易被忽略,偶尔的练习是有必要的.        练习printf /************************************************************************* > File Name: printf.c > Author: > Mail: > Created Time: Wed 11 Feb 2015 01:08:15 AM PST ****************