JNI的输入和输出示例
???? 本文通过两个例子来讲解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);
}
操作结果为:
In C:
c.s = "abc"
In Java:
c.s = "123"
从该例子来看,我认为,jni处理程序就是一个转化数据的过程,难点在于java与本地语言交流时的数据转化。