java jni调用c函数实例分享(java调用c函数)
从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++生成的共享库名一致。