jni的hello world

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 __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

现在开始编写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加上一个.可以在当前目前调用。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值