c语言传图片给java,【Java学习之三】用JNI实现Java和C语言的数据传递

JNI(Java Native Interface),具体定义我就不多说了。做java和android的开发者应该都知道这个东西。原来做项目的时候使用JNI调用过一个加了com组件的MFC窗口。现在需要通过JNI调用C++实现的函数,该函数每隔一段时间给Java端返回一些数据。今天复习了一下JNI,写了一个小的程序。

JNI其实就是把Java类中的方法在java端只保留方法的声明,把方法体也就是实现放到其他语言,如C++、matlab中。

小程序内容是:在C++端有一个int变量,每隔一段时间就+1,并把+1后的值传递给Java端,Java端接收到该数据以后显示到屏幕上。

具体思想:C++声明一个全局变量int num,两个函数一个counter、一个getNum。在counter里用for循环使num++以后Sleep1秒,getNum把num值返回给JNI。Java端使用两个线程,一个线程运行C++端的counter(),一个线程用while(ture)不停的查询num值,如果发现num改变就打印出来。

实现如下:

一、Java添加一个类JniTest

其中声明两个方法counter()和getNum(),不同的就是在声明的时候加上关键字native,代码如下:

package cn.edu.cuit.JNITest;

public class JniTest {

private native void counter();

private native int getNum();

}

二、编译Java类,生成JNI的头文件

cmd进入windows的命令行,使用cd进入到java的工程根目录,如图1:

0818b9ca8b590ca3270a3433284dd417.png

图1 编译生成jni的头文件

在编译的时候要可以省略-jni这个参数,直接用javah就行了。此时要注意的是如果没有package cn.edu.cuit.JNITest则直接使用命令:

>javah JniTest

就可以编译了。但是把JniTest类放到包中以后就要在编译的时候加上包的路径,否则编译不过。

完成编译,查看工程根目录,发现多了一个C语言的头文件cn_edu_cuit_JNITest_JniTest.h。打开此文件内容如下:

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

#include

/* Header for class cn_edu_cuit_JNITest_JniTest */

#ifndef _Included_cn_edu_cuit_JNITest_JniTest

#define _Included_cn_edu_cuit_JNITest_JniTest

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class: cn_edu_cuit_JNITest_JniTest

* Method: counter

* Signature: ()V

*/

JNIEXPORT void JNICALL Java_cn_edu_cuit_JNITest_JniTest_counter

(JNIEnv *, jobject);

/*

* Class: cn_edu_cuit_JNITest_JniTest

* Method: getNum

* Signature: ()I

*/

JNIEXPORT jint JNICALL Java_cn_edu_cuit_JNITest_JniTest_getNum

(JNIEnv *, jobject);

#ifdef __cplusplus

}

#endif

#endif

注意:把#include改成 #include"jni.h"否则后面会遇到编译错误。

在上面的头文件中有两个函数的声明:

JNIEXPORT void JNICALL Java_cn_edu_cuit_JNITest_JniTest_counter (JNIEnv *, jobject);

JNIEXPORT jint JNICALL Java_cn_edu_cuit_JNITest_JniTest_getNum (JNIEnv *, jobject);

就是我们在java端声明的方法对应的JNI的函数声明。

三、用vs2010建立win32的DLL工程,实现c++端的函数体。

vs2010 -> 新建项目 -> Win32项目 -> 下一步 ->应用程序类型选择DLL -> 完成。

在java的jdk安装目录下的jdk1.*** \ \include \\ 下面找到jni.h

在java的jdk1.*** \ \include \\  win32 \\ 下面找到jni_md.h

把两个文件拷贝到刚才建立的C++的工程目录下。

注意用vs2010会有两个JniTest目录,JniTest \\ JniTest 第一个是解决方案的目录,第二哥是工程目录,不要放错位置了。

把刚才生成的cn_edu_cuit_JNITest_JniTest.h也拷贝到JniTest工程目录下面。

在C++的工程头文件中添加这三个头文件;在源文件中建立以个JniTest.cpp的文件,如图2:

0818b9ca8b590ca3270a3433284dd417.png

图2 c++程序的工程文件

在JniTest.cpp 实现这两个方法:

#include "stdafx.h"

#include "jni.h"

#include

#include

#include "cn_edu_cuit_JNItest_JniTest.h"

using namespace std;

int num = 0;

JNIEXPORT void JNICALL Java_cn_edu_cuit_JNITest_JniTest_counter

(JNIEnv *, jobject)

{

for(int i=0; i<100; i++)

{

num++;

Sleep(1000);

}

}

JNIEXPORT jint JNICALL Java_cn_edu_cuit_JNITest_JniTest_getNum

(JNIEnv *, jobject)

{

return num;

}    代码很简单我就不解释了,注意添加相关的.h文件。

编译生成dll文件,注意生成的dll文件是放在解决方案的Debug目录里面,不是在工程目录的Debug里面。之前做JNI用的是VC6.0,生成的dll是在工程目录下的Debug下,用vs2010要注意这个问题。

在Debug目录下发现JniTest.cpp生成的JniTest.dll文件,把它拷贝到java的工程目录>Chart0.6下,也可以拷贝到一个自己专门存放dll的目录中,并在windows的环境变量中添加这个目录。

四、完善Java端代码

在Java类JniTest中load这个dll类库,代码如下;

public class JniTest {

private native void counter();

private native int getNum();

static{

System.loadLibrary("JniTest");

}

然后在继续在类中添加main函数,代码如下:

package cn.edu.cuit.JNITest;

public class JniTest {

private native void counter();

private native int getNum();

static{

System.loadLibrary("JniTest");

}

static int oldNum;

public static void main(String[] args)

{

final JniTest jniTest = new JniTest();

Runnable printRunnable = new Runnable() {

public void run() {

while(true)

{

int newNum = jniTest.getNum();

if(newNum != oldNum)

{

System.out.println(newNum);

oldNum = newNum;

}

try {

Thread.sleep(500);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

};

Thread printThread = new Thread(printRunnable);

Runnable counterRunnable = new Runnable() {

public void run() {

jniTest.counter();

}

};

Thread counterThread = new Thread(counterRunnable);

printThread.start();

counterThread.start();

}

}

main函数中启用两个线程,一个counterThread中调用JniTest类中的counter方法,另一个线程printThread每个0.5秒调用一次getNum,得到一个newNum值,与保存的oldNum值做比较,如果相同则说明C++端的num还没有变化,如果不同则打印出这个值,并更新oldNum的值。

Java在传String给C++或者C语言的时候的处理很多地方都找的到,就是使用GetStringUTFChars和NewStringUTF,我就不详述了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值