您的位置:首页 > 编程语言 > C语言/C++

JNI学习--Java和C、C++之间的数据类型映射之string

2012-03-29 21:58 786 查看
本文主要的内容来源于Java
Native Interface: Programmer's Guide and Specification中的第三章的内容。可通过http://java.sun.com/docs/books/jni/下载该书。

如在编译过程遇到问题,可参考/article/10841695.html

开发环境:

Win7+VS2010+JDK1.6.0_27

1、声明本地方法

新建文件Prompt.java,输入以下内容

class Prompt {
// native method that prints a prompt and reads a line
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");
}


main函数通过调用native method getLine来接收用户输入的字符串

2、编译为class文件

javac Prompt.java

3、生成本地方法的头文件

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


The name of the C function is formed by concatenating the “Java_” prefix, the class name, and the method name.

C函数的名字由前缀Java、类名、方法名连接而成。

The first parameter, the JNIEnv interface

pointer, points to a location that contains a pointer to a function table. Each entry

in the function table points to a JNI function. Native methods always access data

structures in the Java virtual machine through one of the JNI functions.

参数JNIEnv指向一个包含函数表的指针,函数表的指针的每一个入口指向一个JNI函数。native methods通过JNI函数访问Java 虚拟机中的数据结构。





The second argument differs depending on whether the native method is a

static or an instance method. The second argument to an instance native method is

a reference to the object on which the method is invoked, similar to the this

pointer in C++. The second argument to a static native method is a reference to

the class in which the method is defined. Our example, Java_Prompt_getLine,

implements an instance native method. Thus the jobject parameter is a reference

to the object itself.

第二个参数的作用因该native method是static或instance method而不同。对于instance native method,和C++中的this指针类似。对于static native method,它是这个类中定义的方法的一个引用。在我们的例子中,jobject对应object本身。

4、实现本地方法(本文最后将对各种实现方法进行一个简单的介绍)

Java_Prompt_getLine函数接收到prompt传过来的一个jstring类型的参数。jstring代表Java虚拟机中的字符串,和C中的字符指针(char*)是不同的。

你的native method code必须使用合适的JNI函数把jstring对象转换为C/C++类型的字符串。JNI支持Unicode和UTF-8之间的字符串的转换。

Unicode代表的字符是16位的,而UTF-8的编码方案向上兼容7位的ASCII。UTF_8 strings的作用类似NULL-terminated C strings。
新建Prompt.c文件,编写如下内容,推荐使用第二种方法。

第一种实现方法

GetStringUTFChars把jstring转换为UTF-8的格式,在确保原始的字符都是7位的ASCII字符时,可以把转换后的字符串传递给一般的C语言的库函数,比如printf,对于非ASCII字符我可能会在以后讨论,后者参考书中的8.2。

不要忘记检查返回值。因为Java虚拟机的实现需要分配空间给UTF_8字符串,因此,有可能内存分配失败。分配失败时,返回NULL,并且抛出OutOfMemoryError异常。此处,需要显示的返回语句来跳过C函数中后面的语句,因为A pending exception thrown through the JNI does not automatically change control flow in native C code

(native C code的控制流不一定因为异常而自动改变)

当不使用UTF-8字符串时,需要释放。

可以通过在native method中调用JNI function NewStringUTF来构造一个新的java.lang.String实例。
#include <stdio.h>
#include "Prompt.h"
JNIEXPORT jstring JNICALL
Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{
char buf[128];
const jbyte *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);
}

第二种实现方法

The GetStringUTFRegion function takes a starting index and length, both

counted as number of Unicode characters. The function also performs bounds

checking, and raises StringIndexOutOfBoundsException if necessary. In the

above code, we obtained the length from the string reference itself, and are thus

certain that there will be no index overflow. (The above code, however, lacks the

necessary checks to ensure that the prompt string contains less than 128 characters.)

The code is somewhat simpler than using GetStringUTFChars. Because Get-

StringUTFRegion performs no memory allocation, we need not check for possible

out-of-memory conditions. (Again, the above code lacks the necessary checks

to ensure that the user input contains less than 128 characters.)

比使用GetStringUTFChars的代码在某种程度上要简洁,因为GetStringUTFRegion的执行不需要内存分配,我们不需要检查可能的内存溢出情况。

#include <stdio.h>
#include "Prompt.h"
JNIEXPORT jstring JNICALL
Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{
char outbuf[128], inbuf[128];
int len = (*env)->GetStringLength(env, prompt);
(*env)->GetStringUTFRegion(env, prompt, 0, len, outbuf);
printf("%s", outbuf);
scanf("%s", inbuf);
return (*env)->NewStringUTF(env, inbuf);
}

当然,还有其他的函数,比如GetStringCritical,如果使用不当可能出现死锁,如果想学习的话,可以参考书中的3.2部分。



5、编译C的源码,生成本地库

cl -Ic:\java\include -Ic:\java\include\win32 -MD -LD Prompt.c -FePrompt.dll

6、运行程序

java Prompt
结果如下
Type a line: heihei

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