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"); } }
然后使用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 __cplusplus extern "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
首先建立工程的时候,选择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)); }
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加上一个.可以在当前目前调用。