欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-02-20 16:11:16
从c/c++到java,再从java回到c/c++,今天终于有机会了解了连接java、c/c++的桥梁——jni。哈哈!分享一下! 一、简介jni是java native...

从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++生成的共享库名一致。