jni的hello world

来源:互联网 发布:一直回购的淘宝女装店 编辑:程序博客网 时间:2024/04/29 01:40
jni的hello world
JNI是Java Native Interface的缩写,中文为JAVA本地调用。从Java1.1开始,Java Native Interface(JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。 (百科)
第一个jni程序的步骤。
1编写一个java类,其中包含一个native修饰的方法,
public native String readFile(Strig filename);

native修饰的方法和接口定义看起来相同,不能有方法体。

public class Demo1 {static {System.loadLibrary("demolib");//静态导入库,demolib就是后来生成的dll,不过不包含.dll}public native String readFile(Strig filename);public static void main(String[] arge){new Demo().readFile("d:\1.txt");}}

写好java类后,使用javac编译:javac Demo1.java

然后使用javah Demo1 生成.h头文件。

头文件基本格式

/* DO NOT EDIT THIS FILE - it is machine generated */#include "jni.h"//这里javah默认生成是include <jni.h>如果发现编译找不到头文件,可以改成"",但是jni必须包含在工程头文件目录下/* Header for class Demo1 */#ifndef _Included_Demo1#define _Included_Demo1#ifdef __cplusplusextern "C" {#endif/* * Class:     Demo1 * Method:    readFile * Signature: (Ljava/lang/String;)Ljava/lang/String; */
//这个就是给c,c++调动的函数定义JNIEXPORT jstring JNICALL Java_Demo1_readFile  (JNIEnv *, jobject, jstring);#ifdef __cplusplus}#endif#endif

现在开始编写c部分的实现,我这里使用codeblocks,gcc编译器。

首先建立工程的时候,选择Dynamic Link Library 动态链接库

然后导入编译jni需要的头文件,这个jdk安装目录有提供


看图,除了选择圈中的头文件之外,还要选择上图文件夹win32中的jni_md.h头文件,一共是2个头文件,包含进工程里就行了。

c代码:

#include <stdlib.h>#include <string.h>#include "Demo1.h"//导入javah生成的头文件//自定义一个文件读取函数,返回char*char* read(const char* filename){    int defsize=64;    char* buf=(char*)calloc(defsize,sizeof(char));    char fc;    int pos=0;    FILE* file=fopen(filename,"rb");    while ((fc=fgetc(file))!=EOF){         buf[pos++]=fc;        if (pos==defsize){            defsize=2*defsize;            buf=realloc(buf,defsize*sizeof(char));        }    }    return buf;}//这个就是实现了javah生成头文件里的函数。JNIEnv是jni.h定义的结构,jstring是java中String类型到c类型的转换映射。都是定义在jni头文件中。c返回的类型要转换成和java类型相对应。JNIEXPORT jstring JNICALL Java_Demo1_readFile(JNIEnv *env, jobject obj, jstring jstr){    jbyte * temp;//定义jbyte类型字节数组    //GetStringUTFChars是JNIEnv结构里定义的函数,用来转换java的类型参数,并设置了编码格式。    temp=(*env)->GetStringUTFChars(env,jstr,NULL);    //NewStringUTF函数,转换jbyte字节数组为jstring类型,返回给java就是string    return (*env)->NewStringUTF(env,read(temp));}

编译的时候,gcc编译需要指定连接参数,网上有两种参数模式,都测试在codeblocks 使用gcc编译器通过

1:-Wl,--kill-at

2:-Wl,--add-stdcall-alias 

stdcall与_cdecl是两种不同的函数调用约定,区别在函数参数入栈的顺序,由调用函数还是被调用函数将参数弹出栈,以及产生函数修饰名的方法。

jni使用的dll库函数默认使用stdcall调用约定,gcc编译的时候可能不使用stdcall,百度说gcc默认是_cdecl约定,加上这个链接参数就可以了。

我这里选择的是第二种。然后执行java程序,就可以成功调用dll输出,如果报错提示找不到dll,jdk默认dll path路径是window系统dll路径和jdk安装目录下的bin目录,放在这里就可以正常访问,设置jdk dll path加上一个.可以在当前目前调用。

原创粉丝点击