您的位置:首页 > 编程语言 > C语言/C++

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

2015-06-30 14:48 211 查看
                                       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++本地方法
         publicnative
int intMethod(int n);
         publicnative
boolean booleanMethod(boolean bool);
         publicnative String stringMethod(String text);
         publicnative
int intArrayMethod(int[] intArray);
 
         publicstatic
void 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
 */
JNIEXPORTjint
JNICALL Java_JNITest_intMethod(JNIEnv*env,jobject
obj,jint
num)
 {
    returnnum *
num;
 }
  /*
 * Class:    test_JNI_javaCallc_test
 * Method:   booleanMethod
 * Signature: (Z)Z
 */
JNIEXPORTjboolean
JNICALL Java_JNITest_booleanMethod
  (JNIEnv *env,jobjectobj,jboolean
boolean) {
   return!boolean;
}
/*
 * Class:    test_JNI_javaCallc_test
 * Method:   stringMethod
 * Signature:(Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORTjstring
JNICALL Java_JNITest_stringMethod
  (JNIEnv *env,jobjectobj,jstring
string)
  {
        
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
 */
JNIEXPORTjint
JNICALL Java_JNITest_intArrayMethod
  (JNIEnv *env,jobjectobj,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;
}
#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.versio
c19f
n =
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版,即可。

 


三、类型对应关系

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  jni java