JNI--java和C++互相调用

来源:互联网 发布:淘宝虚假交易处罚扣2分 编辑:程序博客网 时间:2024/05/04 13:58

                                       JNI---Java和C++互调

 

                                                                                                                                   何鹏 2015-06-30

一、Java调用C++

    java调用C++,需要将C++代码编译成动态库,通过java虚拟机来加载共享库,进而调用里面的函数。经过以下三个步骤:

①编写调用C++的Java代码,将要调用的函数(本机代码)声明为native

②编写C++实现代码,并编译成动态库

③运行java代码

 

1、编写java测试代码

在Eclipse中建立一个工程,命名为JNITest,并新建一个java文件,命名为JNITest.java。输入以下代码并保存:

--------------------------------------------------------------------------------------------------------------

publicclass JNITest {

         //c/c++本地方法

         publicnativeint intMethod(int n);

         publicnativeboolean booleanMethod(boolean bool);

         publicnative String stringMethod(String text);

         publicnativeint intArrayMethod(int[] intArray);

 

         publicstaticvoid main(String[] args){

                   System.loadLibrary("JNIDLL");

                   JNITestsample =new JNITest();

                   int square = sample.intMethod(5);

                   boolean bool = sample.booleanMethod(true);

                   Stringtext =sample.stringMethod("java");

                   int sum = sample.intArrayMethod(newint[]{ 1, 1, 2, 3, 5, 8, 13 });

                   System.out.println("intMethod:" + square);

                   System.out.println("booleanMethod:" + bool);

                   System.out.println("stringMethod:" + text);

                   System.out.println("intArrayMethod:" + sum);

         }

}

------------------------------------------------------

2、编写C++代码并编译成动态库

在vs2012中建立解决方案,并建立一个项目Win32控制台应用程序JNIDLL,选择时勾选动态库,空项目。


新建一个文件源文件JNITest.cpp,输入:

----------------------------------------------------------------------------------------------------

#include<jni.h>

#include<string.h>

/*Header for class test_JNI_javaCallc_test */

#ifdef__cplusplus

extern"C" {

#endif

 

/*

 * Class:    test_JNI_javaCallc_test

 * Method:   intMethod

 * Signature: (I)I

 */

JNIEXPORTjintJNICALL Java_JNITest_intMethod(JNIEnv*env,jobjectobj,jintnum)

 {

    returnnum *num;

 }

  /*

 * Class:    test_JNI_javaCallc_test

 * Method:   booleanMethod

 * Signature: (Z)Z

 */

JNIEXPORTjbooleanJNICALL Java_JNITest_booleanMethod

  (JNIEnv *env,jobjectobj,jbooleanboolean) {

   return!boolean;

}

/*

 * Class:    test_JNI_javaCallc_test

 * Method:   stringMethod

 * Signature:(Ljava/lang/String;)Ljava/lang/String;

 */

JNIEXPORTjstringJNICALL Java_JNITest_stringMethod

  (JNIEnv *env,jobjectobj,jstringstring)

  {

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

         char cap[128];

         strcpy(cap, str);

         env->ReleaseStringUTFChars(string,str);

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

}

/*

 * Class:    test_JNI_javaCallc_test

 * Method:   intArrayMethod

 * Signature: ([I)I

 */

JNIEXPORTjintJNICALL Java_JNITest_intArrayMethod

  (JNIEnv *env,jobjectobj,jintArrayarray)

  {

     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;

}

#ifdef__cplusplus

}

#endif

----------------------------------------------------------------------------------------------------

这时会找不到jni.h的头文件,配置一下引用目录(jdk的安装目录):

C:\ProgramFiles\Java\jdk1.8.0_11\include;C:\Program Files\Java\jdk1.8.0_11\include\win32;

 

编译,生成一个DLL文件,将该JNIDLL.dll文件拷贝到Eclipse工程下,和src文件夹在同一目录。

3、运行Java代码

点击Eclipse运行第一步建立的工程,即可得到结果

------------------------------------------------------------------

intMethod: 25

booleanMethod:false

stringMethod: JAVA

intArrayMethod: 33

 

问题:

1. 运行Java程序时报:Can't load IA 32-bit .dll ona AMD 64-bit platform。

这是因为jdk是64位版本,而编译的DLL为32位。重新编译dll

在vs2012里,点击菜单 生成--配置管理器:新建64位平台,编译

 

 

将编译完的DLL(在解决方案的x64目录下)重新拷贝到Eclipse项目下,运行。

2.运行时报: Can't find dependent libraries。

 

将运行库这一项去掉。再重新编译

二、C++调用Java

C++调用Java,需要在C++中使用JNI来创建java虚拟机运行java代码,同样经过以下三个步骤:

①编写Java代码,可以被C++调用

②编写C++主程序代码

③运行C++代码

1.编写Java代码

在Eclipse里新建一个java文件,JNI_C_Test.java 输入:

-------------------------------------------------------------------------------------------

publicclass JNI_C_Test

{

   public static int intMethod(int n)  {return n*n;}

 

    public static boolean booleanMethod(booleanbool)  { return !bool;}

                                   

}

保存。在工程的的bin目录下生成JNI_C_Test.class文件

2.编写C++测试代码

在VS2012中新建项目JNI_C_Test,并新建JNI_C_Test.cpp源文件,输入:

---------------------------------------------------------------------------------------------------------

#include<jni.h>

#include<stdio.h>

#include<string.h>

 

#ifdef_WIN32

#definePATH_SEPARATOR';'

#else

#define PATH_SEPARATOR':'

#endif

 

#pragmacomment(lib,"C:/ProgramFiles/Java/jdk1.8.0_11/lib/jvm.lib")

 

int main()

{

         JavaVMOption options[1];

         JNIEnv *env;

         JavaVM *jvm;

         JavaVMInitArgs vm_args;

         long status;

         jclass cls;

         jmethodID mid;

         jint square;

         jboolean not;

 

         options[0].optionString ="-Djava.class.path=.";

         memset(&vm_args, 0, sizeof(vm_args));

         vm_args.version = JNI_VERSION_1_6;

         vm_args.nOptions = 1;

         vm_args.options = options;

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

         if (status != JNI_ERR)

         {

                   cls = env->FindClass("JNI_C_Test");

                   if(cls!=0)

                   {  

                            mid =env->GetStaticMethodID(cls,"intMethod","(I)I");

                            if(mid!=0)

                            { 

                                     square =env->CallStaticIntMethod(cls, mid, 5);

                                     printf("Result of intMethod: %d\n", square);

                            }

 

                            mid =env->GetStaticMethodID(cls,"booleanMethod","(Z)Z");

                            if(mid!=0)

                            { 

                                     not =env->CallStaticBooleanMethod(cls, mid, 1);

                                     printf("Result of booleanMethod: %d\n", not);

                            }

                   }

                  

                   jvm->DestroyJavaVM();

                   return0;

         }

         else

         {

                   return-1;

         }

}

---------------------------------------------------------------------------------------------------------

这时会找不到jni.h的头文件,配置一下引用目录(jdk的安装目录):同上

C:\ProgramFiles\Java\jdk1.8.0_11\include;C:\Program Files\Java\jdk1.8.0_11\include\win32;

另外:这一行:

#pragma comment(lib,"C:/Program Files/Java/jdk1.8.0_11/lib/jvm.lib")

表示要连接到jvm.lib。该路径是Jdk的安装路径,也可以在属性里配置。

编译程序:如果报

error LNK2019: 无法解析的外部符号__imp__JNI_CreateJavaVM@12,该符号在函数_main中被引用

表明链接失败,极有可能是版本不匹配所致。java安装的是64位,而编译的是32位应用程序,按第一节生成x64位平台程序。

3.运行C++程序

1.将第一步生成的JNI_C_Test.class文件拷贝到 项目JNI_C_Test目录下,与JNI_C_Test.cpp同一目录

2.在电脑的环境变量中配置jvm.dll的路径。程序运行时需要连接到该库:

在环境变量path中添加:

;C:\ProgramFiles\Java\jdk1.8.0_11\jre\bin\server


编译运行,按ctrl+F5。即可得出结果:

 

---------------------------------------------------------------------------------------------------------

Result ofintMethod: 25

Result of booleanMethod:0

请按任意键继续. . .

如果出现:应用程序无法正常启动0xc000007b”这个提示框,可能是发布版与debug编译不一致导致的

将编译改为Release版,即可。

 

三、类型对应关系


0 0