C++ 跨語言調用 Java


C++ 跨語言調用 Java  

  Java JDK 提供了 JNI 接口供 C/C++ 程序調用 Java 編譯后的類與方法,主要依賴於頭文件(jni.h) 和 動態庫(jvm.so/jvm.dll),由於 JNI 包含了豐富的接口映射和跨語言的數據通信,非常復雜(坑 深不見底),所以這里只對一個測試程序進行簡單的描述。

  最開始測試的時候選擇了 Window7 64 的環境,安裝的 Java JDK 也是64位的,但是我們都知道 VS 編譯的程序默認情況下都是32位程序,所以我在 LoadLibrary(“jvm.dll”)的時候總是失敗,所以就放棄了 Windows 環境下的測試(懶得去編譯64的程序),最終我使用了 CentOS7 64 完成了測試,並且測試的 Java 版本是 1.7(系統自帶openjdk)。

測試的 Java 代碼如下所示。

1 public class MyTest {
2     private static int magic_counter = 777;
3 
4     public static void callback() {
5     System.out.println("Hello world in java from cplusplus");
6     System.out.print("Magic number: ");
7     System.out.println(magic_counter);
8     }
9 }

  編寫完 Java 測試程序之后,使用命令:javac MyTest.java 對 Java 類進行編譯,並生成相應的 MyTest.class 文件,這個文件所在的位置非常重要,這關系到我們的 C++ JNI 程序能否找到這個文件,因為我們在 C++ JNI 程序中指定了 "-Djava.class.path=." 就是C++程序運行的當前目錄,所有這里我們需要把 MyTest.class 文件拷貝到 C++ 程序的運行目錄中。

  此外由於 JNI 函數需要將調用對象的 Signature ID 傳入,所以我們還需要知道你所有使用對象的 Signature。通過命令: javap -s -p MyTest.class 命令可以獲取后所有函數與變量的 Signature。如下圖所示。

  在編譯程序之前,需要了解你機器上的 Java 版本,及 jni.h 和 jvm.so 所在的位置,方便程序編譯時能夠找到相應的 Java 依賴,這里我使用了 CMake 來輔助編譯,相應的 CMakeList.txt 如下所示。

cmake_minimum_required(VERSION 3.5)
project(testjni)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

include_directories(
        #/opt/program/jdk1.8.0_121/include/linux
        #/opt/program/jdk1.8.0_121/include
        /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.111-2.6.7.2.el7_2.x86_64/include/linux
        /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.111-2.6.7.2.el7_2.x86_64/include

)
link_directories( #
/opt/program/jdk1.8.0_121/jre/lib/amd64/server /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.111-2.6.7.2.el7_2.x86_64/jre/lib/amd64/server/ ) set(SOURCE_FILES main.cpp) add_executable(testjni ${SOURCE_FILES}) target_link_libraries( testjni jvm )

   下面是 C++ JNI 程序的簡單示例,如下所示。

#include <iostream>
#include <jni.h>
#include <memory.h>

int main()
{
    char opt1[] = "-Djava.compiler=NONE"; /** 暫時不知道啥意思,網上抄來的 */
    char opt2[] = "-Djava.class.path=.";  /** 指定Java類編譯后.class文件所在的目錄 */
    char opt3[] = "-verbose:NONE";        /** 暫時不知道啥意思,網上抄來的 */

    JavaVMOption options[3];
    options[0].optionString = opt1; options[0].extraInfo = NULL;
    options[1].optionString = opt2; options[1].extraInfo = NULL;
    options[2].optionString = opt3; options[2].extraInfo = NULL;

    JavaVMInitArgs jargv;
    jargv.version = JNI_VERSION_1_6; /** JDK JNI VERSION*/
    jargv.nOptions = 3;
    jargv.options = options;
    jargv.ignoreUnrecognized = JNI_TRUE;

    JavaVM* jvm = NULL;
    JNIEnv* jenv = NULL;
    jint res = JNI_CreateJavaVM( &jvm, (void**)&jenv, &jargv );
    if ( 0 != res )
        return 1;

    jclass jc = jenv->FindClass( "MyTest" );
    if ( NULL == jc )
        return 1;

    jmethodID jmid = jenv->GetStaticMethodID( jc, "callback", "()V" );
    if ( NULL == jmid )
        return 1;

    jenv->CallStaticVoidMethod( jc, jmid );


    /** 在網上沒有找到任何關於空間相關 JavaVM 和 JNIEnv 資源釋放的描述 */
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

  最終輸出的結果與預期的一致,就到這里,在這么深的坑里,祝大家好運哦。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM