java c 交互_简单介绍Java和C/C++交互

1、Java调用C/C++:

Java代码 [JNITest.java]:

package darcy;

public class JNITest {

static{

System.loadLibrary("Hello");

}

public native void HelloKitty();

public static void main(String[] args){

new JNITest().HelloKitty();

}

}

编译Class文件,然后使用JDK提供的javah工具生成c++层的头文件,当然也可以手写.

javah -jni darcy.JNITest‍

运行后生成的头文件内容[darcy_JNITest.h]:

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

#include 

/* Header for class darcy_JNITest */

#ifndef _Included_darcy_JNITest

#define _Included_darcy_JNITest

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class:     darcy_JNITest

* Method:    HelloKitty

* Signature: ()V

*/

JNIEXPORT void JNICALL Java_darcy_JNITest_HelloKitty

(JNIEnv *, jobject);

#ifdef __cplusplus

}

#endif

#endif

这里我们可以看到,Java层的HelloKitty()方法就对应上C++的Java_darcy_JNITest_HelloKitty,从这里我们可以看出Java层对应的C++层方法签名是Java_为前缀+全限定方法名。

实现这个方法 [darcy_JNITest.cpp]:

#include 

#include "darcy_JNITest.h"

#include 

JNIEXPORT void JNICALL Java_darcy_JNITest_HelloKitty

(JNIEnv *, jobject){

printf("hello kitty\n");

}

下面使用g++编译生成动态链接库libHello.so。对应上Java层调用的System.loadLibrary("Hello");

从实现的c/c++代码上看到,有个jni.h的头文件需要引进来。该文件位于jdk自带的include文件夹里面,如我的在:/usr/java/jdk1.7.0_45/include这个下面.

这里需要注意的是jni.h里面需要依赖于一个叫做jni_md.h的文件,但是可能不再在目录下,向我的在/usr/java/jdk1.7.0_45/include/linux下面,如果报相关的编译错误,

不妨到这里面找一下。

运行命令,生成.so文件:

g++ -shared -fPIC -I /usr/java/jdk1.7.0_45/include darcy_JNITest.cpp -o libHello.so

这里要说明一下关于参数(-fPIC):  这是由于我在编译的时候出现了下面的错误:

/usr/local/bin/ld: /tmp/ccdq1TYq.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC

/tmp/ccdq1TYq.o: error adding symbols: 错误的值

所以才加上去的,不知道是不是跟之前为了编译linux内核而升级了ld这个东西有关,大家在调用该命令的时候可以先把-fPIC去掉试一下。

好了,万事具备,我们运行一下Java程序看看:

java -Djava.library.path=. darcy.JNITest //在=的.表示当前路径

output:hello kitty

文件的路径图:

565bbb18ee6d22f0e21c2d21debed6e0.png

2、C/C++调用Java

Java代码[JNIInvoke.Java]:

package darcy;

public class JNIInvoke{

public static String invoke(){

System.out.println("This is from Java!");

return "Haha";

}

public static void main(String[] args){

System.out.println(invoke());

}

}

我们将要在c++层调用的是invoke()方法,main只是用来测试.

第一步是编译代码,生成JNIInvoke.class。

C++代码[JavaInvoke.cpp]:

#include 

#include 

#include 

#include 

using namespace std;

string  JStringToCString (JNIEnv *env, jstring str);

char* jstringTostring(JNIEnv* env, jstring jstr);

int main(){

JavaVM *jvm;       /* denotes a Java VM */

JNIEnv *env;       /* pointer to native method interface */

JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */

JavaVMOption* options = new JavaVMOption[1];

options[0].optionString = "-Djava.class.path=.:/usr/java/jdk1.7.0_45/lib";

vm_args.version = JNI_VERSION_1_6;

vm_args.nOptions = 1;

vm_args.options = options;

vm_args.ignoreUnrecognized = false;

/* load and initialize a Java VM, return a JNI interface

* pointer in env */

JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);

delete options;

/* invoke the Main.test method using the JNI */

jclass cls = env->FindClass("darcy/JNIInvoke");

jmethodID mid = env->GetStaticMethodID(cls, "invoke", "()Ljava/lang/String;");

jstring result = (jstring)env->CallStaticObjectMethod(cls, mid);

cout<

/* We are done. */

jvm->DestroyJavaVM();

return 0;

}

//把jstring类型转化成c字符串,可不关注该方法

char* jstringTostring(JNIEnv* env, jstring jstr)

{

char* rtn = NULL;

jclass clsstring = env->FindClass("java/lang/String");

jstring strencode = env->NewStringUTF("utf-8");

jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");

jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);

jsize alen = env->GetArrayLength(barr);

jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);

if (alen > 0)

{

rtn = (char*)malloc(alen + 1);

memcpy(rtn, ba, alen);

rtn[alen] = 0;

}

env->ReleaseByteArrayElements(barr, ba, 0);

return rtn;

}

这里有个方法需要注意一下: GetStaticMethodID(), 其中最后一个参数是方法签名(Signature),可以通过javap -s darcy/JNIInvoke看到

0de8185b63a854f563e2f927d4626dc0.png

接下来就是编译C++代码了。

由上面我们可以看到引进了头文件jni.h,同样的也是在/usr/java/jdk1.7.0_45/include/目录下

编译指令:

g++ -g -I/usr/java/jdk1.7.0_45/include/ -L/usr/java/jdk1.7.0_45/jre/lib/amd64/server JavaInvoke.cpp -ljvm

这里用 -g是为了方便gdb的调试,因为JNI的调用出错之后很难定位错误,所以最后在怀疑出错的地方单布调试一下。-L后面是编译需要用到的库的路径。因为在这里要用到libjvm.so这个库。-ljvm就是定位的库了。如果忘记加进来的话,编译过程会报错:

:对‘JNI_CreateJavaVM’未定义的引用

最后,为了运行时能找到libjvm.so这个库,要在环境变量中设置参数:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/java/jdk1.7.0_45/jre/lib/amd64/server

运行: ./a.out

output:

This is from Java! //Java层的打印

Haha //C/C++层的打印

文件的路径图:

9b195a095de0aecc8b437a463132b69e.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值