我们可以看到其中有四个函数声明, 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()这个方法, 是用来在Java和C之间转换字符串的, 因为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, 我们知道struct在C++中和class的功能是几乎一样的,
struct也可以用来定义类, 所以env在C++中是个类对象的指针.

编译和运行

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

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

编译C++版本的dll

>cl -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 -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.0和VS2010的: 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.

JNI设置C++与java的结合(2)的更多相关文章

  1. Android中关于JNI 的学习(三)在JNI层訪问Java端对象

    前面两篇文章简介了JNI层跟Java层的一些相应关系,包含方法名,数据类型和方法名称等,相信在理论层面.可以非常好地帮助我们去了解JNI在Native本地开发中的作用,对JNI的一些概念也有了一个初步 ...

  2. Jni中C++和Java的参数传递 参数对照

    Jni中C++和Java的参数传递 如何使用JNI的一些基本方法和过程在网上多如牛毛,如果你对Jni不甚了解,不知道Jni是做什么的,如何建立一个基本的jni程序,或许可以参考下面下面这些文章:利用V ...

  3. Jni中C++和Java的参数传递

    Jni中C++和Java的参数传递 如何使用JNI的一些基本方法和过程在网上多如牛毛,如果你对Jni不甚了解,不知道Jni是做什么的,如何建立一个基本的jni程序,或许可以参考下面下面这些文章:利用V ...

  4. Jni中C++和Java的参数传递(转)

    如何使用JNI的一些基本方法和过程在网上多如牛毛,如果你对Jni不甚了解,不知道Jni是做什么的,如何建立一个基本的jni程序,或许可以参考下面下面这些文章:利用VC++6.0实现JNI的最简单的例子 ...

  5. Android JNI c/c++调用java 无需新建虚拟机

    近期通过研究SDL源码 得出android JNI  c/c++调用java 无需新建虚拟机: 具体步骤如下 第一步获得:两个参数 JNIEnv和jclass void Java_com_Test_A ...

  6. Linux上设置开机启动Java程序

    在Linux上设置开机启动Java程序,例如:test.jar 在Linux上启动Java程序的命令: nohup java -jar test.jar >/dev/>& & ...

  7. Android JNI中C和JAVA代码之间的互相调用

    关于Android studio中使用NDK/JNI环境和入门:http://blog.csdn.net/quan648997767/article/details/64923143 1. C代码回调 ...

  8. JNI中C调用Java方法

    背景需求 我们需要在JNI的C代码调用Java代码.实现原理:使用JNI提供的反射借口来反射得到Java方法,进行调用. JNI关键方法讲解. 1. 在同一个类中,调用其他方法 JNIEXPORT v ...

  9. JNI字段描述符-Java Native Interface Field Descriptors

    一.JNI字段描述符 "[I" ---  int[] "[[[D" --- double[][][] 如果以一个L开头的描述符,就是类描述符,它后紧跟着类的字符 ...

随机推荐

  1. Lucene查询索引

    索引创建 以新闻文档为例,每条新闻是一个document,新闻有news_id.news_title.news_source.news_url.news_abstract.news_keywords这 ...

  2. cassandra 概述

    摘要 本篇文章主要是介绍cassandra与其他NoSQL的区别以及自身的特点与应用场景.在关系数据库我们没必要选择数据库,通常需要适配oracle/mysql/sql server/db2 等多种数 ...

  3. PHP和MySQL Web开发学习笔记介绍

    前言 从2016年2月1日开始,之后的几个月左右的时间里,我会写一个系列的PHP和MySQL Web开发的学习笔记.我之前一直从事Java语言的开发工作,最近这段时间非常想学习一门语言,就选择了PHP ...

  4. Dynamics CRM2016 升级老版本报“JavaScript Web 资源包含对 Microsoft Dynamics CRM 4.0 (2007) Web 服务终结点的引用”问题的解决办法

    今天在新的服务器上部署了CRM2016 on-premises,并将CRM2015的数据库拷贝过来准备附加后升级,但在升级过程中遇到了如下错误,向导检测到了我的JavaScript Web 资源中包含 ...

  5. SQLite 删除表(http://www.w3cschool.cc/sqlite/sqlite-drop-table.html)

    SQLite 删除表 SQLite 的 DROP TABLE 语句用来删除表定义及其所有相关数据.索引.触发器.约束和该表的权限规范. 使用此命令时要特别注意,因为一旦一个表被删除,表中所有信息也将永 ...

  6. 一个maven项目打多个可执行Jar文件

    使用maven-jar-plugin插件可以将一个maven项目按照需求打出多个可执行的jar文件. pom关键配置如下所示: <plugin> <groupId>org.ap ...

  7. 抽屉效果的实现(DrawerLayout和SlidingMenu的对比)

    在做谷歌电子市场的时候用的是DrawerLayout实现的抽屉效果,在新闻客户端的时候用的是开源框架SlidingMenu来实现的,总的来说,各有个的优点,侧滑(开源框架)实现的效果更好,但是Draw ...

  8. UNIX网络编程——tcp流协议产生的粘包问题和解决方案

    我们在前面曾经说过,发送端可以是一K一K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据,也就是说,应用程序所看到的数据是一个整体 ...

  9. 单幅图像的深度学习,对NYU数据集进行划分

    针对分割问题,官方已经划分好了:http://cs.nyu.edu/~silberman/projects/indoor_scene_seg_sup.html import numpy as np i ...

  10. Servlet之Listener监听器

    Servlet2.5规范共有8中Listener接口,6种Event类型 ServletContextListener接口 [接口方法] contextInitialized()与 contextDe ...