当前位置: 移动技术网 > IT编程>开发语言>Java > java jni调用c函数实例分享(java调用c函数)

java jni调用c函数实例分享(java调用c函数)

2019年07月22日  | 移动技术网IT编程  | 我要评论

从c/c++到java,再从java回到c/c++,今天终于有机会了解了连接java、c/c++的桥梁——jni。哈哈!分享一下!

一、简介
jni是java native interface的简写,可以译作java原生接口。java可以通过jni调用c/c++的库,这对于那些对性能要求比较高的java程序或者java无法处理的任务无疑是一个很好的方式。

二、目的:java代码中调用c/c++代码
三、实现:假设我们的java程序为j2c.java, c程序为j2c.c, java与c之间的通信函数名为write2proc;
              那么write2proc的声明位于j2c.java,实现位于j2c.c;
四、操作
1. 编写并编译java程序

    javac j2c.java => j2c.class
2. 生成c/c++头文件

    javah j2c => j2c.h (安装jdk后,$java_home应该已加入$path, 否则使用绝对路径,例如/usr/bin/javah)

3. 编写对应的c/c++程序:j2c.c

4. 生成c/c++目标文件
    gcc -i/usr/lib/jvm/java-6-openjdk-amd64/include -i/usr/lib/jvm/java-6-openjdk-amd64/include/linux -fpic -c j2c.c => j2c.o
5. 生成c/c++共享库

    gcc -shared -wl,-soname,libj2c.so.1 -o libj2c.so.1.0 j2c.o => libj2c.so.1.0

6. 重命名cp libj2c.so.1.0 libj2c.so => libj2c.so

7. 将共享库加入动态链接库的路径(此例为当前目录)
    export ld_library_path=$ld_library_path:.

8. 执行java程序,实现跨语言通信
     java j2c

 

五、具体过程

1. 编写并编译j2c.java

复制代码 代码如下:

import java.lang.management.managementfactory;
import java.lang.management.runtimemxbean;

public class j2c
{
     static
     {
          try{
               // 此处即为本地方法所在链接库名
               system.loadlibrary("j2c");
          } catch(unsatisfiedlinkerror e)
          {
               system.err.println( "cannot load j2c library:\n " +
               e.tostring() );
          }
     }

     //声明的本地方法
     public static native int write2proc(int pid);

     public static void main(string[] args){

          //获取本进程(即主线程)的pid
          final runtimemxbean runtime = managementfactory.getruntimemxbean();
          final string info = runtime.getname();
          final int index = info.indexof("@");


          if (index != -1) {
               final int pid = integer.parseint(info.substring(0, index));
               system.out.println(info);
               system.out.println(pid);

               write2proc(pid);
          }


          try{
               thread.sleep(8000);
          } catch(interruptedexception e){
               e.printstacktrace();
          }
     }
}

note:java程序中system.loadlibrary参数名表示要载入的c/c++共享库,第6步生成的共享库名必须与该参数一致,即system.loadlibrary(name) 对应共享库名libname.so (共享库名必须以lib开头)

2. 生成c头文件j2c.h:javah j2c

复制代码 代码如下:

/* do not edit this file - it is machine generated */
#include <jni.h>
/* header for class j2c */

#ifndef _included_j2c
#define _included_j2c
#ifdef __cplusplus
extern "c" {
#endif
/*
 * class: j2c
 * method: write2proc
 * signature: (i)i
 */
jniexport jint jnicall java_j2c_write2proc
     (jnienv *, jclass, jint);

#ifdef __cplusplus
}
#endif
#endif

note:1. 头文件自动生成,不要修改它;

2. 函数jniexport jint jnicall java_j2c_write2proc(jnienv *, jclass, jint);

 按照注释的说明是在j2c.java文件的类j2c的方法write2proc处定义,故c程序的实现函数必须与该处签名一致;

3. 编写c程序j2c.c

复制代码 代码如下:

#include <stdio.h>

#include "j2c.h"

jniexport int jnicall java_j2c_write2proc(jnienv * env, jobject arg, jint pid)
{

     printf("current pid is %d\n", pid);

     return 0;

}

4. 编译c程序

因为c程序里#include "j2c.h"而j2c.h又#include <jni.h>, 而gcc里面默认环境并不知道jni.h是什么东西,故编译时需要告诉编译器jni.h的位置( jni.h在jdk 的$java_home/include下面),所以才有了上面的编译参数;

因为使用gcc编译得到动态库,在jni调用的时候,某些情况会有异常, 可尝试改用g++。

总结

1. java中方法的原型声明与c/c++对应的实现文件定义必须一致(可以通过自动生成的c/c++头文件来比较),尤其是类名和方法名;

2. java中system.loadlibrary()载入的共享库名必须与后面c/c++生成的共享库名一致。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网