• 通过JNI实现Java和C++的相互调用(转)


    通过JNI实现JavaC++的相互调用

    一、Java调用C++DLL

    1.    创建Java文件

    创建名为TestNativeJava文件,注意包名。

    package org.druze.test;

    publicclass TestNative {

        publicnativevoid sayHello();

        publicvoid sayHello2(){

           System.out.println("Say Hello From Java");

        }

    }

    如代码所示,对于sayHello方法声明为native,这一部分将由C++的动态库来实现。

    2.    生成class文件

    使用javac org/druze/test/TestNative.java生成class文件

    注意:执行该命令在org所在目录执行。

    3.    使用javah命令生成相应的C++头文件

    使用javah org.druze.test.TestNative生成名为

    org_druze_test_TestNative.h的头文件

    注意:执行该命令在org所在目录执行。

    该头文件的内容如下:

    /* DO NOT EDIT THIS FILE - it is machine generated */

    #include <jni.h>

    /* Header for class org_druze_test_TestNative */

    #ifndef _Included_org_druze_test_TestNative

    #define _Included_org_druze_test_TestNative

    #ifdef __cplusplus

    extern "C" {

    #endif

    /*

     * Class:     org_druze_test_TestNative

     * Method:    sayHello

     * Signature: ()V

     */

    JNIEXPORT void JNICALL Java_org_druze_test_TestNative_sayHello

     (JNIEnv *, jobject);

    #ifdef __cplusplus

    }

    #endif

    #endif

    4.    创建C++解决方案

    此处以VS2008为例。

    新建一个VC++Win32项目,选择如图所示的控制台应用程序。项目名称为NativeCode

    点击确定后,再点击下一步,出现该页面,应用程序类型选择DLL,附加选项选择DLL

    5.    创建号工程之后,将org_druze_test_TestNative.h导入到工程里面,并创建名为source.cpp的源代码,内容如下:

    #include"org_druze_test_TestNative.h"  

    #include<iostream>  

    using namespace std;  

    JNIEXPORT void JNICALL Java_org_druze_test_TestNative_sayHello(JNIEnv *env, jobject obj)

    {  

        cout<<"Hello World!"<<endl;  

    6.    在工具->选项->项目和解决方案->VC++目录菜单中,平台选择Win32,选择“显示以下内容的目录”为“包含文件”,导入jni.hjni_md.h的路径。

    7.    编译,生成NativeCode.dll,并将其copy到环境变量PATH的路径下。

    8.    修改TestNative.java

    package org.druze.test;

    publicclass TestNative {

        publicnativevoid sayHello();

        publicstaticvoid main(String[] args) {

            // 加载动态连接库DLL,如果没有找到的话,则会在运行时报错  

            System.loadLibrary("NativeCode");  

              

            TestNative tnt = new TestNative();  

                  

            tnt.sayHello();  

        }

        publicvoid sayHello2(){

           System.out.println("Say Hello From Java");

        }

    }

    运行,显示“Hello World! 

    9.    注意头文件jni.hjni_md.h可以直接导入到工程中也可以。

    10.注意NativeCode.dll必须放置在java命令能访问的路径中。

    二、C++调用Java

    1.创建TestNative2.Java

    package org.druze.test;

    publicclass TestNative2 {

        publicstaticvoid testPrint(){

           System.out.println("this is from static method");

        }

        publicstaticint testReturn(){

           return 22;

        }

        publicstaticint testInput(int number){

           return 22+number;

        }

        publicint testInstance(int number){

           System.out.println("this is from instance method");

           return 11+number;

        }

    }

    2.VS2008中创建win32控制台的应用程序,命名为NativeCode2,在向导中选择空项目。

    3. 在工具->选项->项目和解决方案->VC++目录菜单中,平台选择Win32,选择“显示以下内容的目录”为“包含文件”,导入jni.hjni_md.h的路径。直接把jni.hjni_md.h导入到工程中。

    4. 在工具->选项->项目和解决方案->VC++目录菜单中,平台选择Win32,选择“显示以下内容的目录”为“包含文件”,导入jvm.lib的路径,并在项目->NativeCode2属性->配置属性->链接器->命令行中添加jvm.lib(这一步或者使用#pragma comment(lib,"jvm.lib")来代替)。或者将直接将jvm.lib添加到工程中。

    5.创建Test.cpp

    #include <jni.h>

    #include <iostream>

    using namespace std;

    int main()

    {

        JavaVMOption options[1];

        JNIEnv * env;

        JavaVM * jvm;

        JavaVMInitArgs vm_args;

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

        vm_args.version = JNI_VERSION_1_6;

        vm_args.nOptions = 1;

        vm_args.options = options;

        vm_args.ignoreUnrecognized = JNI_TRUE;

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

        if (status == JNI_ERR)

        {

            cout<<"Can not create JVM"<<endl;

            return -1;

        }

        printf("Created JVM"n");

        jclass cls = env->FindClass("org/druze/test/TestNative2");

        printf("getCls"n");

         cout<<cls<<endl;

        if (cls !=0)

        {

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

            printf("getMid"n");

            if (mid !=0)

            {

                printf("testReturn"n");

                int result=env->CallStaticIntMethod(cls, mid);

                printf("call over result=%d"n",result);

            }

            mid = env->GetStaticMethodID(cls, "testPrint", "()V");

            if (mid !=0)

            {

                printf("testPrint"n");

                env->CallStaticVoidMethod(cls, mid);

            }

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

            if (mid !=0)

            {

                printf("testInput"n");

                int result=env->CallStaticIntMethod(cls, mid,22);

                printf("call over result=%d"n",result);

            }

            mid = env->GetMethodID(cls,"<init>","()V");

            if (mid != 0)//获取方法成功

            {

                printf("ctro!=0"n");

                jobject obj=env->NewObject(cls, mid);

                printf("new object"n");

                mid = env->GetMethodID(cls, "testInstance","(I)I");

                if (mid!=0)//获取方法成功

                {

                    printf("methodID!=0"n");

                    jint result=env->CallIntMethod( obj, mid,22);

                    cout<<result<<endl;

                }

            }

        }

        jvm->DestroyJavaVM();

        system("Pause");

        return 0;

    }

    6.jvm.dll目录添加到PATH环境变量中,将org/druze/test/TestNative2复制到debug目录下执行。

    7.头文件和库文件的配置VC6VC2008类似,菜单名称有所改变。

    VC6中,配置头文件和库文件的目录在,工具(Tools)->选项(Options)->目录(Directories)里面的头文件”Include files”和库文件”Library files”.添加相应的目录

    工程(Project)->设置(Setting)->链接(Link)->object/module library后面添加jvm.lib

    CodeBlocksProject->Build options->Linker setting and Search directories中配置相应路径。

    8.按如下结构组织可不用配置jvm.dll到环境变量中

    创建存放目录Run(下面的文件目录在JDK安装目录中都能找倒):

    Run(手工建立目录)

    ----bin(手工建立目录)

          ----classic(手工建立目录)

                ----jvm.dll(文件,JDK安装目录中有)

                ----自己的JAR包,如果是class文件把包目录和文件一起拷贝过来

                     如果是jar文件,需要在options[1].optionString = "-Djava.class.path=.;./swt.jar";中设置

                ----JniC.exe,C调用JAVA的程序

          ----hpi.dll(文件,JDK安装目录中有)

          ----ioser12.dll(文件,JDK安装目录中有)

          ----java.dll(文件,JDK安装目录中有)

          ----net.dll(文件,JDK安装目录中有)

          ----verify.dll(文件,JDK安装目录中有)

         ----zip.dll(文件,JDK安装目录中有)

    ----lib(手工建立目录)

          ----zi(目录,JDK安装目录中有,全部拷贝过来)

          ----rt.jar(文件,JDK安装目录中有)

          ----tzmappings(文件,JDK安装目录中有)

    三、JNI代码分析(待续)

  • 相关阅读:
    6月29日训练 题解
    python笔记
    零样本和少样本学习
    基于图的 Affinity Propagation 聚类计算公式详解和代码示例
    pandas.read_csv() 处理 CSV 文件的 6 个有用参数
    100+数据科学面试问题和答案总结 基础知识和数据分析
    基于趋势和季节性的时间序列预测
    Github Copilot 值得购买吗?使用GitHub Copilot进行快速EDA的示例
    ArgMiner:一个用于对论点挖掘数据集进行处理、增强、训练和推理的 PyTorch 的包
    一个简单但是能上分的特征标准化方法
  • 原文地址:https://www.cnblogs.com/GeneralXU/p/1850957.html
Copyright © 2020-2023  润新知