java調用dll(native方法的實現)


  java 中有許多native 方法,下面簡單研究下native 方法的實現以及在java 中調用native 方法。

  下面以簡單的操作加減乘除實現

1. 新建java 類

源碼如下:

package com.zd.bx;

public class Operation {

    public native int add(int a, int b);
}

2. javah 生成 .h 頭文件

.h 文件是c++的頭文件

E:\ideaspace\mvnpro\target\classes>javah com.zd.bx.Operation

最后會在當前目錄生成: com_zd_bx_Operation.h, 內容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_zd_bx_Operation */

#ifndef _Included_com_zd_bx_Operation
#define _Included_com_zd_bx_Operation
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_zd_bx_Operation
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_zd_bx_Operation_add
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

3. 用visual studio 生成dll 鏈接庫

1. 新建項目(選擇c++ -> 動態鏈接庫)

 然后輸入名稱:

 2. 生成的目錄結構如下:

 3. 將上面生成的com_zd_bx_Operation.h 拷貝到項目目錄下

(1) 拷貝到: E:\visualstudio\namespace\OperationDLL\OperationDLL,  就是和 dllmain.cpp 同級目錄

(2) 然后點擊頭文件, 選擇添加現有項, 選擇上面添加進去的com_zd_bx_Operation.h 文件

 4. 打開com_zd_bx_Operation.h 會報錯找不到jni.h 

 5. jni.h 以及相關實現是jdk 提供的, 所以需要引入%jdk%/include, 以及%jdk%/include/win32 目錄作為附加包含目錄

(1) 選擇項目-》 屬性 -》c++ -》常規-》附加包含目錄

 (2) 選中 %java%/include 和 %java%/include/win32 目錄

(3) 應用之后再次打開com_zd_bx_Operation.h 可以看到不會編譯報錯

6. 編輯dllmain.cpp, 將容修改為如下:

// dllmain.cpp : 定義 DLL 應用程序的入口點。
#include "pch.h"
#include "com_zd_bx_operation.h"

JNIEXPORT jint JNICALL Java_com_zd_bx_Operation_add
(JNIEnv* env, jobject obj, jint a, jint b) {
    return a + b;
}

7. 點擊導航欄 生成 -》 生成解決方案

控制台顯示如下:(會顯示dll 的生成位置)

已啟動生成…
1>------ 已啟動生成: 項目: OperationDLL, 配置: Debug x64 ------
1>dllmain.cpp
1>  正在創建庫 E:\visualstudio\namespace\OperationDLL\x64\Debug\OperationDLL.lib 和對象 E:\visualstudio\namespace\OperationDLL\x64\Debug\OperationDLL.exp
1>OperationDLL.vcxproj -> E:\visualstudio\namespace\OperationDLL\x64\Debug\OperationDLL.dll
========== 生成: 成功 1 個,失敗 0 個,最新 0 個,跳過 0 個 ==========

  也就是生成了所需要的dll 庫

4. java 調用dll

1. 將上面的dll 拷貝到 java工程目錄下:

 2. 編寫測試代碼:

package com.zd.bx;

public class PlainTest {

    static {
        System.loadLibrary("OperationDLL");
    }

    public static void main(String[] args) {
        System.out.println(new Operation().add(1, 3));
    }
}

結果:

4

5.  改進

1. c++ 的cout 也可以輸出到控制台, 比如修改 dllmain.cpp

// dllmain.cpp : 定義 DLL 應用程序的入口點。
#include "pch.h"
#include "com_zd_bx_operation.h"
#include <iostream>
using namespace std;

JNIEXPORT jint JNICALL Java_com_zd_bx_Operation_add
(JNIEnv* env, jobject obj, jint a, jint b) {
    int version = env->GetVersion();
    cout << "env " << env << endl;
    cout << "env->GetVersion() " << version << endl;
    cout << "obj " << obj << endl;
    return a + b;
}

  上面代碼調用 env.GetVersion() 方法。 然后打印相關對象內存地址。 關於env 和 obj 有哪些方法以及屬性可以Ctrl + 鼠標左鍵進去查看,類似於java 查看類方法。

重新生成dll 后測試如下:

env 000002625ABCFA00
env->GetVersion() 65544
obj 000000EDD66FF2D0
4

2. 可以將c++實現和主類進行隔離。 

(1) VS中選擇頭文件然后添加 Operation.h 頭文件

 內容如下:

#pragma once

int add(int a, int b);

(2) 源文件選擇添加信件項選擇 cpp 文件

 內容如下:

#include "pch.h"
#include <stdio.h>;
#include "Operation.h";
using namespace std;

int add(int a, int b) {
    printf("cpp print a: %i b: %i", a, b);
    return a + b;
}

(3) 修改dllmain.cpp

// dllmain.cpp : 定義 DLL 應用程序的入口點。
#include "pch.h"
#include "com_zd_bx_operation.h"
#include "Operation.h"

JNIEXPORT jint JNICALL Java_com_zd_bx_Operation_add
(JNIEnv* env, jobject obj, jint a, jint b) {
    return add(a, b);
}

(4) 最終目錄結構如下:

 (5) 重新生成dll 后測試結果如下:

 

總結:

  .h 文件我理解類似於java 的接口, 只給出定義。 具體的cpp 文件引入之后可以給出方法的實現。 然后別的模塊引入相關頭文件即可(頭文件的方法只能有一個cpp 中有,否則會報錯)。 我們用javah 生成的也是.h 頭文件, 所以我們需要做的就是生成實現的方法, 然后導出到dll 里。

 


免責聲明!

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



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