使用JNI集成java与native程序

系统 1580 0


当我们开始接触JNI但是还不熟悉的时候,也许会这样几个问题:

  1. Java程序和native程序的数据类型通常是不一样的,它们怎么相互映射的呢?
  2. 怎么在native方法中访问java方法传递过来的数据呢?
  3. 在native方法中可以创建java对象吗?
  4. 如何把结果返回给调用它的java方法?

读完本文你将会明白如上问题的来龙去脉。首先我在重复一下如何编写JNI相关的应用程序,我们必须在java方法中声明一个native的方法,比如 public native String getLine(String prompt);这个方法具有的两个特点是,引入了关键字native,它的意思是这个方法的实现由其他的语言实现,比如c/c++等。另外这个方法是以 分号结尾的,表明这个方法不包括实现。我们在上篇文章已经知道使用javah命令可以得到我们需要的header文件。下面给出java程序和相关的.h 文件的代码

//Prompt.java
class Prompt {
private native String getLine(String prompt);
public static void main(String args[]) {
Prompt p = new Prompt();
String input = p.getLine("Type a line: ");
System.out.println("User typed: " + input);
}
static {
System.loadLibrary("prompt");
}
}

//Prompt.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Prompt */

#ifndef _Included_Prompt
#define _Included_Prompt
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Prompt
* Method: getLine
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_Prompt_getLine
(JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

我们可以看到在Prompt.h文件中定义了我们要实现的函数的原型,我们主要关心两点一个是方法名称另一个是方法的参数,方法的名称为Java_Prompt_getLine,它是由如下四部分组成

看看方法的参数,由三个参数组成分别是JNIEnv *, jobject, jstring。JNIEnv是一个JNI接口指针,它事实上是由函数表组成的,我们可以使用JNIEnv来访问java对象。jobject是当前类的 的引用,想当与java中的this。最后一个参数是jstring,代表了我们java方法中的String prompt。

在编写native方法的时候,无论是java基本类型还是对象我们都不能在c/c++中直接使用,必须要转成相对应得类型,下面给出基本数据类型的对应关系。

 

Java Type Native Type Size in bits
boolean jboolean 8, unsigned
byte jbyte 8
char jchar 16, unsigned
short jshort 16
int jint 32
long jlong 64
float jfloat 32
double jdouble 64
void void n/a

关于java对象,JNI都是把它映射为jobject,为了减少编程的错误可能性,同时从jobject中实现了一些子类型,比如jstring等。

下面我们讲述,如何在native方法中访问java方法的参数,如何在native方法中创建java对象。我们必须清楚地知道,在访问java参数的 时候,首先要把它转换为相应的类型,比如参数String prompt在.h文件中为jstring。但是在实现这个方法的时候,我们不能直接对jstring进行操作,因为它与char *是不同的,我们要通过JNIEnv提供的方法把它转换为char *。比如
char buf[128];
const char *str = env->GetStringUTFChars(prompt, 0);
printf("%s", str);
注 意一点,我们必须要主动释放我们得到的char *,否则会造成内存泄漏。释放的方法还是通过JNIenv提供的方法,(*env).ReleaseStringUTFChars(prompt, str);。JNIEnv同样提供了构造String的方法,使得我们可以返回给调用者一个String类型的返回值
gets(buf);
return (*env).NewStringUTF(buf);

下面给出native实现的源代码(c++代码)
#include <stdio.h>
#include <jni.h>
#include "Prompt.h"

JNIEXPORT jstring JNICALL
Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{
char buf[128];
const char *str = env->GetStringUTFChars(prompt, 0);
printf("%s", str);
(*env).ReleaseStringUTFChars(prompt, str);
gets(buf);
return (*env).NewStringUTF(buf);
}
在VC++中,你可以创建一个dll工程,最后把得到的prompt.dll方到Prompt.class的目录,运行java Prompt,系统就会提示你输入一行字符。输入回车后则可以回显到控制台。

使用JNI集成java与native程序


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论