java与c 之jni编程小结
--- jack 于湖大
1. 什么是 jni
jni是java native interface的缩写。从java 1.1开始,jni标准成为java平台的一部分,它允许java和其他语言进行交互。jni一开始为c和c 而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。
使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。
关于 jni 的用法很简单,有点像 java 里的 reflect 的工作机制,有兴趣的朋友可以参看更详细的书
2. jni 开发步骤
l 编写带有native声明的方法的java类
l 使用javac 或 ide(jbuilder,eclipse等)编译所编写的java类
l 使用javah -jni java类名生成扩展名为h的头文件
l 使用c 实现本地方法,对调用签名可用 javap –s –p [类全名] 查看(开发 c 动态链接库本例是用的 vc6)
注意要从 jdk下面的 include 文件夹中把 jni.h和 jni_md.h 两个文件 copy 到你的 vc 工程里
l 在 java 中 load 动态链接库文件,调用 native 方法
3. 开发实例
1. 编写 java 类: (我的 ide 是 eclipse)
/**
* jack.wang
*/
package org.jm.jni;
import java.util.arraylist;
/**
* @author jack.wang
* @time mar 1, 2008
*/
public class backgroundprocess {
static {
system.loadlibrary("org_jm_jni_backgroundprocess");
}
// 三个 native 方法和一个 int 变量
public native boolean checkvalid();
public native void processdata(backgroundprocess bg);
public native void processgarbage(string[] bg);
public int num = 5;
// c 中可以调用的方法
public string backprocess(arraylist p) {
system.out.println("这是 java 里的方法,在 c 中调用。");
system.out.println("这个方法,是 java 中 native checkvalid 方法调用的。");
return "look up process ->" p;
}
public static void main(string[] args) {
string[] array = new string[4];
array[0] = "jack";
array[1] = "maggie";
array[2] = "rocket";
array[3] = "tom";
backgroundprocess bgp = new backgroundprocess();
// 调用 c dll 中定义的方法。
bgp.checkvalid();// 该方法回调 java 中的 backprocess 方法
bgp.processdata(bgp);
bgp.processgarbage(array);
// c dll 改变了该变量
system.out.println("number 现在的值是: " bgp.num);
}
}
2. 生成 c 的头文件(javah 命令生成,用javap –s –p [类全名] 命令查看java 方法签名)
/* do not edit this file - it is machine generated */
#include "jni.h"
/* header for class org_jm_jni_backgroundprocess */
#ifndef _included_org_jm_jni_backgroundprocess
#define _included_org_jm_jni_backgroundprocess
#ifdef __cplusplus
extern "c" {
#endif
/*
* class: org_jm_jni_backgroundprocess
* method: checkvalid
* signature: ()z
*/
jniexport jboolean jnicall java_org_jm_jni_backgroundprocess_checkvalid
(jnienv *, jobject);
/*
* class: org_jm_jni_backgroundprocess
* method: processdata
* signature: (lorg/jm/jni/backgroundprocess;)v
*/
jniexport void jnicall java_org_jm_jni_backgroundprocess_processdata
(jnienv *, jobject, jobject);
/*
* class: org_jm_jni_backgroundprocess
* method: processgarbage
* signature: ([ljava/lang/string;)v
*/
jniexport void jnicall java_org_jm_jni_backgroundprocess_processgarbage
(jnienv *, jobject, jobjectarray);
#ifdef __cplusplus
}
#endif
#endif
3. 开发 c dll 的原文件 (记得要加入 jni.h 和 jni_md.h 两个文件)
发布 dll 文件, 我是配置了 path 环境变量
#include "org_jm_jni_backgroundprocess.h"
#include
#include
#include "string.h"
char* jstringtostring(jnienv* env, jstring jstr)
{
char* rtn = null;
jclass clsstring = env->findclass("java/lang/string");
jstring strencode = env->newstringutf("utf-8");
jmethodid mid = env->getmethodid(clsstring, "getbytes", "(ljava/lang/string;)[b");
jbytearray barr= (jbytearray)env->callobjectmethod(jstr, mid, strencode);
jsize alen = env->getarraylength(barr);
jbyte* ba = env->getbytearrayelements(barr, jni_false);
if (alen > 0)
{
rtn = (char*)malloc(alen 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->releasebytearrayelements(barr, ba, 0);
return rtn;
}
//char* to jstring
jstring stojstring(jnienv* env, const char* pat)
{
jclass strclass = env->findclass("ljava/lang/string;");
jmethodid ctorid = env->getmethodid(strclass, "", "([bljava/lang/string;)v");
jbytearray bytes = env->newbytearray(strlen(pat));
env->setbytearrayregion(bytes, 0, strlen(pat), (jbyte*)pat);
jstring encoding = env->newstringutf("utf-8");
return (jstring)env->newobject(strclass, ctorid, bytes, encoding);
}
/*
* class: org_jm_jni_backgroundprocess
* method: checkvalid
* signature: ()z
*/
jniexport jboolean jnicall java_org_jm_jni_backgroundprocess_checkvalid
(jnienv *env, jobject obj){
jclass bgpclass=env->getobjectclass(obj);
jmethodid methodid=env->getmethodid(bgpclass,"backprocess","(ljava/util/arraylist;)ljava/lang/string;");
jobject str=env->callobjectmethod(obj,methodid,null);
jfieldid fieldid=env->getfieldid(bgpclass,"num","i");
jint number=env->getintfield(obj,fieldid);
cout << "number 值是: " <
env->setintfield(obj,fieldid,100l);
return 1;
}
/*
* class: org_jm_jni_backgroundprocess
* method: processdata
* signature: (lorg/jm/jni/backgroundprocess;)v
*/
jniexport void jnicall java_org_jm_jni_backgroundprocess_processdata
(jnienv *env, jobject, jobject){
cout<< "this function do nothing " << endl;
}
/*
* class: org_jm_jni_backgroundprocess
* method: processgarbage
* signature: ([ljava/lang/string;)v
*/
jniexport void jnicall java_org_jm_jni_backgroundprocess_processgarbage
(jnienv *env, jobject, jobjectarray array){
jint size=env->getarraylength(array);
cout << "数组大小是: " << size << endl;
jstring tempobj=null;
char *pszstr1 = null;
for(int i=0;i
cout << "current value is : " << i << endl;
tempobj=(jstring)env->getobjectarrayelement(array,i);
const char * chars =env->getstringutfchars(tempobj, 0);
cout << chars << endl;
}
}
4. 现在你可以在 java 和 c 之间互调了
本博客为学习交流用,凡未注明引用的均为本人作品,转载请注明出处,如有凯发k8网页登录的版权问题请及时通知。由于博客时间仓促,错误之处敬请谅解,有任何意见可给我留言,愿共同学习进步。