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

JNI技术——JNI传递对象和JNI传递中文字符串

2010-01-23 15:38 375 查看
JNI本地方法支持java对象的传递。本文就java如何传递对象给C++的DLL,在C++中又如何获取java对象的变量,如何调用java函数以及如何接收java传递的中文字符串问题做一个简单的描述。

 

假设我们需要传递如下所示对象:

package Editor;

class MyObject
{
    int value1;
    String value2;
   
    MyObject() { }
   
    MyObject(int v1, String v2)
    {
        value1 = v1;
        value2 = v2;
    }
   
    public void setValue(String v2)
    {
        value2 = v2;
    }
}

public class Editor
{
    // 定义本地方法,可以是static也可以是非static
    public native static int add(int x, int y);
   
    // 定义本地方法,传入一个对象和一个字符串(如何传递中文)
    public native static void transferObject(MyObject obj, String inStr);
   
    static
    {
        // 加载动态链接库,不需要写扩展名,由JVM自动识别
        System.loadLibrary("TestDLL");
    }
}

 

在C++中即可按照如下方式实现本地方法:

#include "Editor.h"
#include "Utility.h"
#include "string"

JNIEXPORT jint JNICALL Java_Editor_Editor_add
  (JNIEnv *, jclass, jint x, jint y)
{
    return x + y;
}

JNIEXPORT void JNICALL Java_Editor_Editor_transferObject
  (JNIEnv * pJNIEnv, jclass j, jobject jobj, jstring jsIn)
{
    jclass jcls = pJNIEnv->GetObjectClass( jobj );

    /**
     * 获得变量和方法的定义,其中第三个参数是该变量的类型所对应的标签。
     *
     * boolean      Z
     * byte              B
     * char             C
     * short            S
     * int                  I
     * long              L
     * float              F
     * double         D
     * void               V
     * object           L包名/类名;
     * Array             [数组类型
     * method        (参数类型)返回类型
     */
    jfieldID jfid1 = pJNIEnv->GetFieldID( jcls, "value1", "I" );
    jfieldID jfid2 = pJNIEnv->GetFieldID( jcls, "value2", "Ljava/lang/String;");
    jmethodID jmid = pJNIEnv->GetMethodID( jcls, "setValue", "(Ljava/lang/String;)V" );

    // 获得变量的值
    jint value1 = pJNIEnv->GetIntField( jobj, jfid1 );
    jstring value2 = ( jstring )pJNIEnv->GetObjectField( jobj, jfid2 );

    // 获得字符串,但是下面的函数会对中文输入产生乱码,需要自己手动转换
    // char * pcValue2 = pJNIEnv->GetStringUTFChars ( value2, NULL );
    char * pcValue2 = JStringToCharArray( pJNIEnv, value2 );  
    printf( "C++:value1 = %d, value2 = %s  ", value1, pcValue2 );

    char * pcIn = JStringToCharArray( pJNIEnv, jsIn );
    printf( "C++:输入参数(inStr) = %s  ", pcIn );

    // 修改传入对象的成员变量
    pJNIEnv->SetIntField( jobj, jfid1, 5 );

    // 调用传入对象的函数修改成员变量
    pJNIEnv->CallVoidMethod( jobj, jmid, pJNIEnv->NewStringUTF( "Chinese!" ) );
}

由于java中的中文字符编码为UNICODE,为宽字节字符集,而C++的中文字符编码为ANSII,为多字节字符集,需要对传入的中文参数执行转换。JStringToCharArray函数实现如下:

#include "jni.h"
#include "Windows.h"

char * JStringToCharArray(JNIEnv * pJNIEnv, jstring jstr)
{
    jsize len = pJNIEnv->GetStringLength( jstr );
    const jchar * jcstr = pJNIEnv->GetStringChars( jstr, NULL );

    int size = 0;
    char * str = ( char * )malloc( len * 2 + 1 );
    if ( (size = WideCharToMultiByte( CP_ACP, 0, LPCWSTR( jcstr ), len, str, len * 2 + 1, NULL, NULL ) ) == 0 )
        return NULL;

    pJNIEnv->ReleaseStringChars( jstr, jcstr );

    str[ size ] = 0;
    return str;
}
测试代码:

package Editor;

public class TestEditor
{
    public static void main(String[] args)
    {
        int ret = Editor.add(10, 10);
        System.out.println("add(10, 10) = " + ret);
       
        MyObject obj = new MyObject(10, "测试test");
       
        System.out.println("调用DLL前:obj.value1 = " + obj.value1 + ", obj.value2 = " + obj.value2);
           
        Editor.transferObject(obj, "测试test");
           
        System.out.println("调用DLL后:obj.value1 = " + obj.value1 + ", obj.value2 = " + obj.value2);
    }
}

运行后输出:

add(10, 10) = 20
调用DLL前:obj.value1 = 10, obj.value2 = 测试test
调用DLL后:obj.value1 = 5, obj.value2 = Chinese!
C++输出:value1 = 10, value2 = 测试test
C++输出:这是一个传入参数(inStr) = 测试test

 

由此可见,C++不仅能接收java对象、java字符串、也能调用java函数。如果合理的利用JNI,C++还能接收java数组、返回java对象、返回java数组。。。

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