在windows环境下使用Java调用c++的实现
vs新建一个NativaInvoke的dll工程,拷贝jdk目录下(C:\Program Files\Java\jdk1.8.0_66\include)的jni.h jni_md.h jawt_md.h 到工程代码目录
新建一个Java类代码如下:
public class NativaInvoke
{
//声明调用c++的实现方法,方法必须用native修饰,并且方法不可以有实现体
public native void ShowInfo(int idx, String strMessge);
public native void F1();
public native void F2(int value);
public native void F3(double value);
public native String F4(String value);
public native void ModifyJavaMemberData();
public native void RecallJavaMethod();
public int number = 10;
public static void main(String[] args) {
//load NativaInvoke.dll
System.loadLibrary("NativaInvoke");
NativaInvoke nativaInvoke = new NativaInvoke();
String str="wowowo";
nativaInvoke.F1();
nativaInvoke.F2(10);
nativaInvoke.F3(3.14159);
nativaInvoke.ShowInfo(1,"ls");
System.out.println(nativaInvoke.F4(str));
//
System.out.println(nativaInvoke.number);
nativaInvoke.ModifyJavaMemberData();
System.out.println(nativaInvoke.number);
nativaInvoke.RecallJavaMethod();
}
public double Add(double value1,double value2){
return value1+value2;
}
}
使用javah命令来生成c++需要的头文件,生成的头文件如下
/* DO NOT EDIT THIS FILE - it is machine generated */
//<>改成""
#include "jni.h"
/* Header for class NativaInvoke */
#ifndef _Included_NativaInvoke
#define _Included_NativaInvoke
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: NativaInvoke
* Method: ShowInfo
* Signature: (ILjava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_NativaInvoke_ShowInfo
(JNIEnv *, jobject, jint, jstring);
/*
* Class: NativaInvoke
* Method: F1
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_NativaInvoke_F1
(JNIEnv *, jobject);
/*
* Class: NativaInvoke
* Method: F2
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_NativaInvoke_F2
(JNIEnv *, jobject, jint);
/*
* Class: NativaInvoke
* Method: F3
* Signature: (D)V
*/
JNIEXPORT void JNICALL Java_NativaInvoke_F3
(JNIEnv *, jobject, jdouble);
/*
* Class: NativaInvoke
* Method: F4
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_NativaInvoke_F4
(JNIEnv *, jobject, jstring);
/*
* Class: NativaInvoke
* Method: ModifyJavaMemberData
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_NativaInvoke_ModifyJavaMemberData
(JNIEnv *, jobject);
/*
* Class: NativaInvoke
* Method: RecallJavaMethod
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_NativaInvoke_RecallJavaMethod
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
在c++工程中实现函数,如下
// NativaInvoke.cpp : 定义 DLL 应用程序的导出函数。
//
#include "stdafx.h"
#include "NativaInvoke.h"
#include <iostream>
using namespace std;
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_NativaInvoke_ShowInfo(JNIEnv* pEnv, jobject, jint value1, jstring value2)
{
//jstring 转换到char* 后才能正常使用
const char *strTemp = pEnv->GetStringUTFChars(value2, 0);
std::cout << "Invoke Java_NativaInvoke_ShowInfo(" << value1 << ":" << strTemp <<")"<< std::endl;
pEnv->ReleaseStringUTFChars(value2, strTemp);
}
/*
* Class: NativaInvoke
* Method: F1
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_NativaInvoke_F1(JNIEnv *, jobject)
{
std::cout << "Invoke Java_NativaInvoke_F1()"<< std::endl;
}
/*
* Class: NativaInvoke
* Method: F2
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_NativaInvoke_F2(JNIEnv *, jobject, jint value)
{
std::cout << "Invoke Java_NativaInvoke_F2("<<value<<")" << std::endl;
}
/*
* Class: NativaInvoke
* Method: F3
* Signature: (D)V
*/
JNIEXPORT void JNICALL Java_NativaInvoke_F3(JNIEnv *, jobject, jdouble value)
{
std::cout << "Invoke Java_NativaInvoke_F3(" << value << ")" << std::endl;
}
/*
* Class: NativaInvoke
* Method: F4
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_NativaInvoke_F4(JNIEnv * pEnv, jobject, jstring value)
{
//jstring 不能直接使用 需要转换
const char* str;
str = pEnv->GetStringUTFChars(value, false);
if (str == NULL) {
return NULL; /* OutOfMemoryError already thrown */
}
std::cout << "Invoke Java_NativaInvoke_F4(" << str << ")" << std::endl;
pEnv->ReleaseStringUTFChars(value, str);
//返回字符串到Java
char* tmpstr = "return string succeeded From C++";
jstring strReturn = pEnv->NewStringUTF(tmpstr);
return strReturn;
}
/*
* Class: NativaInvoke
* Method: ModifyJavaMemberData
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT void JNICALL Java_NativaInvoke_ModifyJavaMemberData(JNIEnv * pEnv, jobject obj)
{
//c++修改Java成员变量值
jclass clazz_TestNative = pEnv->GetObjectClass(obj);
//获取属性对象
jfieldID idNumber = pEnv->GetFieldID(clazz_TestNative,"number","I");
// jint number = pEnv->GetIntField(obj,idNumber);
pEnv->SetIntField(obj,idNumber,1000L);
}
//c++ 调用Java成员方法
JNIEXPORT void JNICALL Java_NativaInvoke_RecallJavaMethod(JNIEnv * pEnv, jobject obj)
{
//获取类对象
jclass objClass = pEnv->GetObjectClass(obj);
//获取方法对象
jmethodID idMethod = pEnv->GetMethodID(objClass, "Add", "(DD)D");
double value1 = 20;
double value2 = 24.234;
jdouble dReturnValue = pEnv->CallDoubleMethod(obj, idMethod, value1, value2);
std::cout << "Invoke java double Add("<<value1<<","<<value2<<")="<< dReturnValue <<std::endl;
}
#ifdef __cplusplus
}
#endif
编译生成dll文件NativaInvoke.dll,放在Java代码同目录下
javac编译Java源码 java NativaInvoke执行Java代码 一切正常
有时候会遇到java.lang.UnsatisfiedLinkError:这样的错误,原因是找不到对应的函数实现,仔细检查代码是否正确或加载的dll名称及路径是否正确