您的位置:首页 > 编程语言 > Java开发

JNI处理是一个转化数据的过程,难点在于java与本地语言交流时的数据转化

2012-05-17 20:20 579 查看
本文通过两个例子来讲解JNI的一个输入/输出应用。首先看一个String的输入输出的例子,下面是java部分的代码

public 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");

}

}

native方法是调用c/c++等语言接口的方法,Static静态代码块加载dll文件,本例中dll文件的名称是Prompt.dll。

编译这个java类,得到class文件,用javah命令生成头文件(javah -jni 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

以下是一个C语言编写的小代码

#include <jni.h>

#include <stdio.h>

#include "Prompt.h"

JNIEXPORT jstring JNICALL

Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)

{

char buf[128];

const char *str;

str = (*env)->GetStringUTFChars(env, prompt, NULL);

if (str == NULL) {

return NULL;

}

printf("%s", str);

(*env)->ReleaseStringUTFChars(env, prompt, str);

scanf("%s", buf);

return (*env)->NewStringUTF(env, buf);

}

用vc里的cl可生成dll文件。

本程序运行过程:

运行java程序,main方法内有三句:

Prompt p = new Prompt();

建立本类实例,这将执行静态块加载dll文件。

String input = p.getLine("Type a line: ");

执行本地方法,我认为这将到头文件Prompt.h中去找执行的方法,于是就找到了这句

JNIEXPORT jstring JNICALL Java_Prompt_getLine(JNIEnv *, jobject, jstring);

进而执行c语言中的方法

执行本方法最困惑的是“如何将java中本地方法的那个String类型的参数转化成C语言中要接收的参数,C语言返回的参数又要转化为java的String”。

在 jni.h(应该是在jdk中include文件架下的一个头文件)中定义了基本类型的转换(int - jint , float - jfloat 等),本地代码会调用jni的函数获取相应的内容,例如本例中的GetStringUTFChars函数,该函数将JString转化为了C语言中的String,然后可以作为标准的C语言变量使用,处理后返回一个jString变量。

System.out.println("User typed: " + input);

打印结果。

下面看另外一个例子。

java代码:

public class InstanceFieldAccess {

private String s;

private native void accessField();

public static void main(String args[]) {

InstanceFieldAccess c = new InstanceFieldAccess();

c.setS("abc");

c.accessField();

System.out.println("In Java:");

System.out.println(" c.s = \"" + c.getS() + "\"");

}

static {

System.loadLibrary("InstanceFieldAccess");

}

public void setS(String s)

{

this.s = s;

}

public String getS()

{

return s;

)

}

以下是C语言代码:

#include <jni.h>

#include <stdio.h>

#include "InstanceFieldAccess.h"

JNIEXPORT void JNICALL

Java_InstanceFieldAccess_accessField(JNIEnv *env, jobject obj)

{

jfieldID fid; /* store the field ID */

jstring jstr;

const char *str;

//获取java类实例

jclass cls = (*env)->GetObjectClass(env, obj);

printf("In C:\n");

//获取java类实例的变量s

fid = (*env)->GetFieldID(env, cls, "s",

"Ljava/lang/String;");

if (fid == NULL) {

return; /* failed to find the field */

}

//获取变量s的值

jstr = (*env)->GetObjectField(env, obj, fid);

//将变量s的值转化为标准c语言能处理的类型

str = (*env)->GetStringUTFChars(env, jstr, 0);

if (str == NULL) {

return; /* out of memory */

}

printf(" c.s = \"%s\"\n", str);

//将str转化为jString 类型

(*env)->ReleaseStringUTFChars(env, jstr, str);

//修改jString 值为 “123”;

jstr = (*env)->NewStringUTF(env, "123");

(*env)->SetObjectField(env, obj, fid, jstr);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: