JNI---Java和C++互调
何鹏 2015-06-30
java调用C++,需要将C++代码编译成动态库,通过java虚拟机来加载共享库,进而调用里面的函数。经过以下三个步骤:
①编写调用C++的Java代码,将要调用的函数(本机代码)声明为native
②编写C++实现代码,并编译成动态库
③运行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);
}
}
------------------------------------------------------
在vs2012中建立解决方案,并建立一个项目Win32控制台应用程序JNIDLL,选择时勾选动态库,空项目。
新建一个文件源文件JNITest.cpp,输入:
----------------------------------------------------------------------------------------------------
#include
#include
/*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
{
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文件夹在同一目录。
点击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++中使用JNI来创建java虚拟机运行java代码,同样经过以下三个步骤:
①编写Java代码,可以被C++调用
②编写C++主程序代码
③运行C++代码
在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文件
在VS2012中新建项目JNI_C_Test,并新建JNI_C_Test.cpp源文件,输入:
---------------------------------------------------------------------------------------------------------
#include
#include
#include
#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位平台程序。
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版,即可。