zoukankan      html  css  js  c++  java
  • 1 通过JNI混合使用Java和C++ -----> 操作字符串

    JNI(Java Native Interface)是Java语言的一部分,可以访问非Java语言编写的程序,也可以用于在C++程序中执行Java代码。

    步骤:

    1>  编写带有native声明方法的Java类,并且该方法只定义不实现,后期由c++负责实现:

    // HelloCpp.java

    public class HelloCpp

    {

        // ...

       public native void callCpp();

        // ...

    }

    2>  由于后期的C++实现代码最终会被编译为一个动态库.dll,因此需要在Java类中定义一个静态代码块,提前加载该动态库,假设动态的名字为hellocpp.dll:

    // HelloCpp.java

    public class HelloCpp

    {

        static

        {

           System.loadLibrary("hellocpp");

        }

        public native void callCpp();

        // ...

    }

    3>  在Java类中定义main方法调用该native方法:

    // HelloCpp.java

    public class HelloCpp

    {

        static

        {

           System.loadLibrary("hellocpp");

        }

        public native void callCpp();

        public static void main(String[] args)

        {

           System.out.println("***** JNI Test *****");

           HelloCpp instance = new HelloCpp();

           instance.callCpp();      // 调用native方法

        }

    }

    4>  编译包含native方法的Java类,生成class字节码文件:

    javac HelloCpp.java        // 生成HelloCpp.class

    5>  生成与native方法对应的.h头文件:

    javah –jni HelloCpp         // 生成HelloCpp对于的头文件HelloCpp.h

    // HelloCpp.h

    /* DO NOT EDIT THIS FILE - it is machine generated */

    #include <jni.h>

    /* Header for class HelloCpp */

    #ifndef _Included_HelloCpp

    #define _Included_HelloCpp

    #ifdef __cplusplus

    extern "C" {

    #endif

    /*

     * Class:     HelloCpp

     * Method:    callCpp

     * Signature: ()V

     */

    JNIEXPORT void JNICALL Java_HelloCpp_callCpp(JNIEnv* env, jobject this);

    #ifdef __cplusplus

    }

    #endif

    #endif

    6>  使用C++实现native方法:

    // HelloCpp.cpp

    #include "HelloCpp.h"

    #include <jni.h>

    #include <iostream>

    JNIEXPORT void JNICALL Java_HelloCpp_callCpp(JNIEnv* env, jobject this)

    {

        std::cout << "C++ Implementation" << std::endl;

    }

    7>  编译生成动态库hellocpp.dll:

    g++ -Wl,--kill-at –shared –I D:jdk1.7.0_75include –I D:jdk1.7.0_75includewin32 HelloCpp.cpp –o hellocpp.dll

    8>  调用hellocpp.dll来运行Java程序:

    Java HelloCpp

    结果如下:

    ***** JNI Test *****

    C++ Implementation

     

    说明:

    JNIEXPORT void JNICALL Java_HelloCpp_callCpp(JNIEnv* env, jobject this);

    JNIWXPORT和JNICALL是宏。

    JNIEnv*指向一个位置,该位置包含一个指向函数表的指针,表中的每一项都是一个指向JNI函数的指针,native方法通过JNI函数访问JVM的中的数据 ,如下所示:

    第二个参数对于非静态方法为jobject,对于静态方法为jclass。jobject表示调用native方法对象自身的引用,如同C++中的this指针;jclass表示定义native方法的类的引用。

    如下介绍带有参数返回值的native方法:

    // Prompt.java

     1 class Prompt
     2 {
     3     static
     4     {
     5         System.loadLibrary("Prompt");
     6     }
     7     private native String GetLine(String prompt);
     8     
     9     public static void main(String[] args)
    10     {
    11         Prompt p = new Prompt();
    12         String input = p.GetLine("Enter a line:");
    13         System.out.println("Your Input is: " + input);
    14     }
    15 }
        

    // Prompt.h

     1 /* DO NOT EDIT THIS FILE - it is machine generated */
     2 #include <jni.h>
     3 /* Header for class Prompt */
     4 
     5 #ifndef _Included_Prompt
     6 #define _Included_Prompt
     7 #ifdef __cplusplus
     8 extern "C" {
     9 #endif
    10 /*
    11  * Class:     Prompt
    12  * Method:    GetLine
    13  * Signature: (Ljava/lang/String;)Ljava/lang/String;
    14  */
    15 JNIEXPORT jstring JNICALL Java_Prompt_GetLine(JNIEnv* env, jobject _this, jstring prompt);
    16 
    17 #ifdef __cplusplus
    18 }
    19 #endif
    20 #endif

    // Prompt.cpp

     1 #include "Prompt.h"
     2 #include <iostream>
     3 
     4 JNIEXPORT jstring JNICALL Java_Prompt_GetLine(JNIEnv* env, jobject _this, jstring prompt)
     5 {
     6     char buf[1024];
     7     const char* str;
     8     str = env->GetStringUTFChars(prompt, NULL);            /* 获得传入的字符串,将其转换为native Strings */
     9     if(str == NULL)                                        /* str == NULL意味着JVM为native String分配内存失败 */
    10     {
    11         return NULL;
    12     }
    13     std::cout << str;                                        /* 显示传入的字符串参数 prompt */ 
    14     env->ReleaseStringUTFChars(prompt, str);                /* 通知JVM释放String所占的内存 */
    15     
    16     std::cin.get(buf, 1024);
    17     return env->NewStringUTF(buf);                        /* 构造新的Java.lang.String,如果JVM分配内存失败,则抛出OutOfMemoryError,并且返回NULL */
    18 }

    补充信息:

    :: UTF-8字符串以’’结尾,而Unicode字符串则不是。如果需要获得Unicode格式的jstring的长度,可以使用GetStringLength;如果需要获得UTF-8格式的jstring的长度,可以先使用GetStringUTFChars,在其结果上使用strlen,或者直接使用GetStringUTFLength

    :: GetStringUTFChars的第二个参数为jboolean *isCopy,其指向分配的内存空间,如果isCopy被设为JNI_TRUE,那么返回的String是Java String的一个副本;如果被设为JNI_FALSE,那么返回一个指向Java String本身的指针,此时不允许修改返回的String。

    :: 函数对Get/ReleaseStringCritical的作用于Get/ReleaseStringChars类似,但是对于程序员而言,该函数对之间的代码相当于“临界区”。在该“临界区”内,native代码不能调用任何的JNI函数,否则将引起当前线程阻塞。

    :: GetStringRegion/GetStringUTFRegion将Unicode格式的String复制到预分配的缓冲区中,由于不需要JVM分配内存,因此也就不需要释放操作:

     1 JNIEXPORT jstring JNICALL Java_Prompt_GetLine(JNIEnv* env, jobject _this, jstring prompt)
     2 {
     3     char inbuf[1024], outbuf[1024];
     4     int len = env->GetStringUTFLength(prompt);
     5     env->GetStringUTFRegion(prompt, 0, len, outbuf);
     6     std::cout << outbuf;
     7     
     8     std::cin.get(inbuf, 1024);
     9     return env->NewStringUTF(inbuf);    
    10 }

    总结:

    1>  数据类型对应关系表:

    Java 类型

    本地 C 类型

    实际表示的 C 类型(Win32

    boolean

    jboolean

    unsigned char

    byte

    jbyte

    signed char

    char

    jchar

    unsigned short

    short

    jshort

    short

    int

    jint

    long

    long

    jlong

    __int64

    float

    jfloat

    float

    double

    jdouble

    double

    void

    void

    N/A

    2>  JNI字符串函数

    JNI函数

    描述

    版本

    GetStringChars

    ReleaseStringChars

    获得/释放一个Unicode格式的字符串指针,可能返回一个字符串的副本

    JDK 1.1

    GetStringUTFChars

    ReleaseStringUTFChars

    获得/释放一个UTF-8格式的字符串指针,可能返回一个字符串的副本

    JDK 1.1

    GetStringLength

    返回Unicode格式字符串的长度

    JDK 1.1

    GetStringUTFLength

    返回UTF-8格式字符串的长度

    JDK 1.1

    NewString

    根据Unicode格式的C字符串创建一个Java字符串

    JDK 1.1

    NewStringUTF

    根据UTF-8格式的C字符串创建一个Java字符串

    JDK 1.1

    GetStringCritical

    ReleaseStringCritical

    获得/释放一个Unicode格式的字符串指针,可能返回一个字符串的副本【在该函数对区间内,不能使用任何JNI函数】

    JDK 1.2

    GetStringRegion

    将Unicode格式的String复制到预分配的缓冲区中

    JDK 1.2

    GetStringUTFRegion

    将UTF-8格式的String复制到预分配的缓冲区中

    JDK 1.2

  • 相关阅读:
    POJ2524+并查集
    POJ3697+BFS+hash存边
    POJ1151+线段树+扫描线
    POJ2528+线段树
    ubuntu 和 win7 远程登陆 + vnc登陆
    POJ3690+位运算
    POJ3283+字典树
    POJ3282+模拟
    POJ2349+prim
    2016.6.13
  • 原文地址:https://www.cnblogs.com/benxintuzi/p/4593137.html
Copyright © 2011-2022 走看看