CentOS Java C JNI

使用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>
#include "IntArray.h"
/* Header for class IntArray */

#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 /home/oracle/jdk1.8.0_05/include -I /home/oracle/jdk1.8.0_05/include/linux/ -fPIC -shared -o libIntArray.so IntArray.c

其中 -I后面是java的include文件夹地址,请根据您具体的java版本以及安装路径作相应改变;
-f后面的PIC表示生成的库中符号是与位置无关的(PIC就是Position Independent Code),关于PIC,可以参考这篇文章
http://www.gentoo.org/proj/en/hardened/pic-guide.xml

-shared表示共享,共享库后缀名.so可以认为是shared object的简称;
-o libIntArray.so,可以理解为编译后输出libIntArray.so库。

六、使用Java运行程序
java IntArray

可能出现以下结果:

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  注:该方法只在当前会话窗口有效,切换到另外一个终端窗口,则需要重新指定共享库路径。也可直接在环境变量中加入:LD_LIBRARY_PATH=.:$ORACLE_HOME/lib:/usr/lib64:/usr/lib:/usr/local/lib64:/usr/local/lib  命令行中使用:source ~/.bash_profile  使当前增加的环境变量生效

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

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

--------------------------------------------

文章来源于:http://www.2cto.com/os/201108/101048.html

时间: 2025-01-02 00:06:00

CentOS Java C JNI的相关文章

Centos JAVA Eclipse

wget http://download.oracle.com/otn-pub/java/jdk/8u5-b13/jdk-8u5-linux-i586.tar.gz vi /etc/profile 在文件后添加类似与一下的代码即可,注意:你的设置目录可能不同需修改. JAVA_HOME=/usr/java/jdk1.8.0JRE_HOME=/usr/java/jdk1.8.0/jrePATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/binCLASSPATH=.:$JAVA_

java通过JNI接口调用C语言-初级

JNI(java native interface):即java本地调用C的接口. 先看整体运行: 下面是过程: #vim test.java 1 public class test{ 2 3 public native static int add(int a, int b); //指明本地函数 4 static{ 5 System.loadLibrary("add"); //指定动态库 6 }; 7 8 public static void main(String args[]){

java通过JNI调用c++代码

java通过JNI调用c++代码 1 用java约定接口,生成头文件 创建JniHelloWorld.java public class JniHelloWorld { public JniHelloWorld(){ } public native void sayHello(String name); } 生成头文件供c++使用 javah-jni JniHelloWorld 产生JniHelloWorld.h文件,里面是用c++代码规定了接口形式. 2生成动态链接库文件(http://blo

Java通过jni技术支持c、c++调用使用整理

最近在公司搞终端5.0,说要对c++版本sdk封装一个java版的sdk,可是团队没有搞java的,于是赶鸭子上架,临时学习几天,整了一下:感觉还挺有意思的,于是整理一下: 为什么要使用java支持对c.c++的调用? 众所周知Java语言是一门支持跨平台解释型语言:#.java通过javac编译生成生成#.class字节码,运行过程依赖java虚拟机执行字节码生成虚拟机的执行指令,最终通过虚拟机操控所在平台,完成其设计的功能:其优点很明显,支持跨平台:其缺点也很明显,执行效率底,并且不支持平台

【Java,JNI】学习汇总

START FROM 2014/5/12 for memory of wenchuan [1]关于java内存的三篇文章: 1,内存模型http://www.cnblogs.com/aigongsi/archive/2012/04/26/2470296.html 而内存模型就是规定了一个规则,处理器如何同主内存同步数据的一个规则. 2,垃圾回收http://www.cnblogs.com/aigongsi/archive/2012/04/06/2434771.html 要点:jvm采用找root

【Java的JNI快速学习教程】

1. JNI简介 JNI是Java Native Interface的英文缩写,意为Java本地接口. 问题来源:由于Java编写底层的应用较难实现,在一些实时性要求非常高的部分Java较难胜任(实时性要求高的地方目前还未涉及,实时性这类话题有待考究). 解决办法:Java使用JNI可以调用现有的本地库(C/C++开发任何和系统相关的程序和类库),极大地灵活Java的开发. 2. JNI快速学习教程 2.1 问题: 使用JNI写一段代码,实现string_Java_Test_helloworld

Java通过JNI调用dll详细过程(转)

源:Java通过JNI调用dll详细过程 最近项目有这样一个需求,在已有的CS软件中添加一个链接,将当前登录用户的用户名加密后放在url地址中,在BS的login方法里通过解密判断,如果为合法用户则无需再次登录直接进入平台,CS软件方提供了一个加密解密的dll文件,我们需要在action中通过该dll解密,那么就涉及到java调用dll的问题. 首先我选择了JNI方式(因为网上说的另两种方式Jawin, Jacob更不会),大体流程如下: 1.写一个java的class,在类里声明所调用的库名称

JAVA的JNI调用

由于JNI调用C和调用C++差不多,而且C++中可以混合写C代码,所以这里主要是写关于JNI调用C++的部分. 一般步骤: 先是写普通的Java类,其中包括本地方法调用.  然后编译这个Java类,调用javah命令,生成.h头文件 接着,就是实现头文件中的函数:实现过程中有点比较麻烦,要知道JNI中JAVA和C/C++的类型转换,比如数组类型的转换,基本类型的转换等,最好是看文档,或者网上找相关资料. 源代码链接:http://files.cnblogs.com/GDUT/jni-demo.r

centos java安装

1.下载java:jdk-7u51-linux-x64.tar.gz http://www.kuaipan.cn/file/id_175485603436042793.htm?source=1 2.移动jdk-7u51-linux-x64.tar.gz到/usr/local tar -zxvf jdk-7u51-linux-x64.tar.gz 3.设置环境变量 vi /etc/profile 加入以下代码 export JAVA_HOME=/usr/local/java/jdk1.7.0_45