JNI——Java调用DLL

基本概念

JNI其实是Java Native Interface的简称,也就是java本地接口。它提供了若干的API实现了和Java和其他语言的通信(主要是C&C++)。对于那些对性能要求比较高的Java程序或者Java无法处理的任务无疑是一个很好的方式。

实验方案

假设我们的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后, JAVAHOME 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

//windows 环境下实现
cl -I %JAVA_HOME%/include -c J2C.c

具体CL操作及环境配置:点击链接

  1. 生成C/C++共享库
    gcc -shared -Wl,-soname,libj2c.so.1 -o libj2c.so.1.0 J2C.o => libj2c.so.1.0
//重命名
cp libj2c.so.1.0 libj2c.so => libj2c.so

//windows 下实现
cl /LD J2C
  1. 将共享库加入动态链接库的路径(此例为当前目录)

建议将生成的dll/so 文件放在项目的根目录

共享库加入动态链接库的具体方法

  1. 执行Java程序,实现跨语言通信
    java J2C

具体实现代码

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();
          }
     }
}

Java程序中System.loadLibrary参数名表示要载入的C/C++共享库,第6步生成的共享库名必须与该参数一致,即System.loadLibrary(Name) 对应共享库名libName.so (共享库名必须以lib开头)||Windows中共享库名为Name.dll

生成的J2C.h


/* 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

头文件自动生成,不要修改它;
按照注释的说明是在J2C.java文件的类J2C的方法write2proc处定义,故C程序的实现函数必须与该处签名一致

C程序J2C.c


#include <stdio.h>  
 #include "J2C.h" 
 JNIEXPORT long JNICALL Java_J2C_write2proc(JNIEnv * env, jobject arg, jint pid) 
{ 
      printf("current pid is %d\n", pid); 
      return 0; 
 }

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


总结

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

  2. Java中System.loadLibrary()载入的共享库名必须与后面C/C++生成的共享库名一致。

常见错误

JNI java.lang.UnsatisfiedLinkError

详情:点击链接

Can’t load IA 32-bit .dll on a AMD 64-bit platform

详情:点击链接

类型错误

注意int通过javah 自动生成的.h文件中是Jint,是long型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值