服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

使用jni集成java与native程序

    jni入门教程之helloworld篇一文中介绍了如何一步步编写jni相关的应用程序,并没有更多的介绍相关的机制,本文主要介绍如何使用jni把java程序和native程序结合起来。

    当我们开始接触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,它是由如下四部分组成
使用jni集成java与native程序(图一)

 

 

 

 

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

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

java typenative typesize in bits
booleanjboolean8, unsigned
bytejbyte8
charjchar16, unsigned
shortjshort16
intjint32
longjlong64
floatjfloat32
doublejdouble64
voidvoidn/a

    关于java对象,jni都是把它映射为jobject,为了减少编程的错误可能性,同时从jobject中实现了一些子类型,比如jstring等。
使用jni集成java与native程序(图二)

点击查看大图

 

 

 

 

 

 

 

 

    下面我们讲述,如何在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,系统就会提示你输入一行字符。输入回车后则可以回显到控制台。

扫描关注微信公众号