• JNI设置C++与java的结合(2)


    我们可以看到其中有四个函数声明, Java_完整类名_方法名完整类名包括了包名例如demo.Sample1是完整类名对应的这里就是demo_Sample1.

    在注释中我们可以看到这样一个东西 Signature, 这个是方法的签名关于Signature, 下面通过一个表格来说明.

    java类型

    Signature

    备注

    boolean

    Z


    byte

    B


    char

    C


    short

    S


    int

    I


    long

    L


    float

    F


    double

    D


    void

    V


    object

    L/分割的完整类名

    例如: Ljava/lang/String表示String类型

    Array

    [签名

    例如: [I表示int数组, [Ljava/lang/String表示String数组

    Method

    (参数签名)返回类型签名

    例如: ([I)I表示参数类型为int数组返回int类型的方法

    上面头文件的第一个函数声明

    JNIEXPORT jint JNICALL Java_Sample1_intMethod (JNIEnv *, jobject, jint);

    注释中的签名是 Signature: (I)I

    在每个函数的参数列表中都有JNIEnv * jobject两个参数这两个参数稍候说明.

    实现头文件中的函数

    可以使用C语言来实现也可以使用C++来实现下面先说说C语言的实现.

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    #include "Sample1.h"

    #include <string.h>

     

    JNIEXPORT jint JNICALL Java_Sample1_intMethod

      (JNIEnv *env, jobject obj, jint num)

    {

        return num * num;

    }

     

    JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod

      (JNIEnv *env, jobject obj, jboolean   boolean)

    {

        return !boolean;

    }

     

    JNIEXPORT jstring JNICALL Java_Sample1_stringMethod

      (JNIEnv *env, jobject obj, jstring string)

    {

        const char* str = (*env)->GetStringUTFChars(env,   string, 0);

        char cap[128];

        strcpy(cap, str);

        (*env)->ReleaseStringUTFChars(env,   string, 0);

        return (*env)->NewStringUTF(env,   strupr(cap));

    }

     

    JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod

      (JNIEnv *env, jobject obj, jintArray array)

    {

        int i, sum = 0;

        jsize len =   (*env)->GetArrayLength(env, array);

        jint *body =   (*env)->GetIntArrayElements(env, array, 0);

         

        for (i = 0; i < len;   ++i)

        {

            sum +=   body[i];

        }

        (*env)->ReleaseIntArrayElements(env,   array, body, 0);

        return sum;

    }

    (*env)->GetStringUTFChars()这个方法是用来在JavaC之间转换字符串的因为Java本身都使用了双字节的字符C语言本身都是单字节的字符所以需要进行转换.

    JNIEnv *是每个函数都有的参数它包含了很多有用的方法使用起来类似Java的反射也提供了这样一个编码转换的函数.

    GetStringUTFChars()NewStringUTF(), 第一个是从UTF8转换为C的编码格式第二个是根据C的字符串返回一个UTF8字符串.

    ReleaseStringUTFChars()是用来释放对象的Java中有虚拟机进行垃圾回收但是在C语言中这些对象必须手动回收否则可能造成内存泄漏.

    函数的名字一眼看到就可以猜出功能, jni.h中的大部分函数名都是这样.

    如果是C++的话这段代码该怎么写?

    下面是C++的代码

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    #include "Sample1.h"

    #include <string.h>

     

    JNIEXPORT jint JNICALL Java_Sample1_intMethod

      (JNIEnv *env, jobject obj, jint num)

    {

        return num * num;

    }

     

    JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod

      (JNIEnv *env, jobject obj, jboolean   boolean)

    {

        return !boolean;

    }

     

    JNIEXPORT jstring JNICALL Java_Sample1_stringMethod

      (JNIEnv *env, jobject obj, jstring string)

    {

        const char* str = env->GetStringUTFChars(string,   0);

        char cap[128];

        strcpy(cap, str);

        env->ReleaseStringUTFChars(string,   0);

        return env->NewStringUTF(strupr(cap));

    }

     

    JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod

      (JNIEnv *env, jobject obj, jintArray array)

    {

        int i, sum = 0;

        jsize len =   env->GetArrayLength(array);

        jint *body =   env->GetIntArrayElements(array, 0);

         

        for (i = 0; i < len;   ++i)

        {

            sum +=   body[i];

        }

        env->ReleaseIntArrayElements(array,   body, 0);

        return sum;

    }

     

    上述两端代码非常相似只有一个不同点

    C代码: (*env)->GetStringUTFChars(env, string, 0);

    C++代码: env->GetStringUTFChars(string, 0);

    C语言中使用的是结构体的函数指针而在C++中使用的还是struct, 我们知道structC++中和class的功能是几乎一样的, struct也可以用来定义类所以envC++中是个类对象的指针.

    编译和运行

    这里使用的是微软编译器编译C语言版的dll

    >cl -I%JAVA_HOME%include -I%JAVA_HOME%includewin32 -LD Sample1.c -FeSample1.dll

    编译C++版本的dll

    >cl -I%JAVA_HOME%include -I%JAVA_HOME%includewin32 -LD Sample1.cpp -FeSample1.dll

    运行

    >java Sample1

    注意: 64位版本的JDK可能会在运行时报错:

    java.lang.UnsatisfiedLinkError: ...Sample1.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform

    如果您有这样的错误请使用32位的JDK来重新运行.

    运行结果如下:

    intMethod: 25

    booleanMethod: false

    stringMethod: JAVA

    intArrayMethod: 36

     源代码下载: Sample1.zip

    运行其中的build&run.bat文件即可如有错误请根据实际情况修改其中的一些参数.

    DLL工程文件VC6.0VS2010: VC6.0&VS2010.zip

    参考文献:

    1. Scott Stricker,  JNI 进行 Java 编程,      http://www.ibm.com/developerworks/cn/education/java/j-jni/section2.html

    2. JDK 6u30 docs, Java Native      Interface Specification, Chapter 3 JNI Types and Data Structures, Type      Signatures.

  • 相关阅读:
    《图解CSS3》笔记5 媒体与Responsive设计
    理论篇 前端MVC、MVP、MVVM思考1
    AngularJS篇 $resource使用笔记
    《图解CSS3》笔记4 animation动画
    Prim
    邻接矩阵与邻接表
    差分约束
    SPFA
    floyd
    Kosaraju
  • 原文地址:https://www.cnblogs.com/LoongEmbedded/p/5298370.html
Copyright © 2020-2023  润新知