JNI Java调用C++

本文介绍如何在Windows环境下通过Java调用C++的方法。具体步骤包括:创建DLL工程并复制必要的JNI头文件;定义Java接口声明所需C++方法;使用javah生成C++头文件;在C++中实现对应方法;编译生成DLL;最后在Java中加载并调用这些方法。

在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名称及路径是否正确

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值