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
    评论
Java 中调用 C 语言编写的动态库,需要使用 Java Native Interface(JNI)。在 JNI 中有一些函数可以用来处理指针参数,例如:GetDirectBufferAddress() 和 GetPrimitiveArrayCritical() 等。 如果 C 语言中的函数需要传递指针参数,可以在 JNI 中使用 ByteBuffer 类型来表示指针。在 Java 中,使用 ByteBuffer 类型创建一个缓冲区对象,并将其传递JNI 函数。在 C 语言中,使用 void* 类型来接收 ByteBuffer 类型的指针参数。在 C 语言中通过操作这个 void* 类型的指针,就可以访问 Java 中的 ByteBuffer 对象。 以下是一个使用 JNI 调用 C 语言编写的动态库的示例代码: Java 代码: ``` import java.nio.ByteBuffer; public class TestJNI { static { System.loadLibrary("test"); // 加载 C 语言编写的动态库 } private native void test(ByteBuffer buffer); // 声明 JNI 方法 public static void main(String[] args) { TestJNI test = new TestJNI(); ByteBuffer buffer = ByteBuffer.allocateDirect(1024); // 创建一个 ByteBuffer 对象 test.test(buffer); // 调用 JNI 方法 } } ``` C 语言代码: ``` #include <stdio.h> #include <jni.h> JNIEXPORT void JNICALL Java_TestJNI_test(JNIEnv *env, jobject obj, jobject buffer) { char *ptr = (char *) (*env)->GetDirectBufferAddress(env, buffer); // 获取 ByteBuffer 对象的指针 if (ptr == NULL) { return; } // 操作 ByteBuffer 对象 for (int i = 0; i < 1024; i++) { ptr[i] = i % 256; } } ``` 需要注意的是,在 C 语言中,需要使用 JNIEnv 指针和 jobject 对象来访问 Java 对象。在上面的示例代码中,JNIEnv 指针和 jobject 对象分别被命名为 env 和 obj。在 C 语言中,通过 (*env) 操作符来访问 JNIEnv 指针所指向的对象。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值