java調(diào)用動(dòng)態(tài)庫dll詳細(xì)示例代碼
數(shù)據(jù)類型對應(yīng)關(guān)系
| Java Type | C Type |
|---|---|
| boolean | int |
| byte | char |
| char | wchar_t |
| short | short |
| double | double |
| float | float |
| String | char* |
JNI 調(diào)用 dll
示例
- 包jni中新建java文件,JniDemo.java
package jni;
public class JniDemo {
public native static void set(int i);
public native static int get();
}
- 使用javah命令生成頭文件(jni_JniDemo.h)
javah jni.JniDemo
vs2017創(chuàng)建項(xiàng)目 - Visual C++ - Windows 桌面 - 動(dòng)態(tài)鏈接庫(DLL)
新建項(xiàng)目JniDemo
注:選錯(cuò)了工程類型報(bào)錯(cuò)(UnsatisfiedLinkError: dll: 此操作僅在應(yīng)用容器上下文中有效。)拷貝jni_JniDemo.h,jni.h,jni_md.h至vs工程cpp文件目錄下
jni.h在D:\Java\jdk1.8.0_111\include\jni.h
jni_md.h在D:\Java\jdk1.8.0_111\include\win32\jni_md.h編輯文件
修改文件jni_JniDemo.h:
#include <jni.h> 改為 #include "jni.h"
修改文件JniDemo.cpp:
#include "stdafx.h"
#include "jni_JniDemo.h"
int number = 0;
JNIEXPORT void JNICALL Java_jni_JniDemo_set
(JNIEnv *, jclass, jint i)
{
number = i;
}
JNIEXPORT jint JNICALL Java_jni_JniDemo_get
(JNIEnv *, jclass)
{
return number;
}
生成64位dll庫
文件位置:D:\vsrepos\JniDemo\Release\JniDemo.dll把64位dll庫拷貝至Java JniDemo項(xiàng)目根目錄下,修改JniDemo.java
public class JniDemo {
static{
System.loadLibrary("JniDemo");
}
public native static void set(int i);
public native static int get();
public static void main(String[] args) {
// System.out.println(System.getProperty("java.library.path"));
set(100);
System.out.println(get());
}
}
缺點(diǎn)
如果有一個(gè)現(xiàn)有的.dll/.so文件,如果使用JNI技術(shù)調(diào)用,我們首先需要另外使用C語言寫一個(gè).dll/.so共享庫,使用SUN規(guī)定的數(shù)據(jù)結(jié)構(gòu)替代C語言的數(shù)據(jù)結(jié)構(gòu),調(diào)用已有的 dll/so中公布的函數(shù)。
然后再在Java中載入這個(gè)適配器dll/so,再編寫Java native函數(shù)作為dll中函數(shù)的代理。
Jnative 調(diào)用 dll
Jnative是對JNI技術(shù)進(jìn)行了封裝,更加方便的讓java去調(diào)用DLL
JNA調(diào)用dll
JNA全稱Java Native Access
https://blog.csdn.net/gwd1154978352/article/details/55097376/
JNA中,它提供了一個(gè)動(dòng)態(tài)的C語言編寫的轉(zhuǎn)發(fā)器,可以自動(dòng)實(shí)現(xiàn)Java和C的數(shù)據(jù)類型映射。不再需要編寫C動(dòng)態(tài)鏈接庫。
地址:https://github.com/java-native-access/jna
<!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna -->
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.3.1</version>
</dependency
JNA沒辦法直接調(diào)用類方法,需要將類方法“取出來”重新封裝一遍。同時(shí)為了保持類的特性,每個(gè)方法增加一個(gè)參數(shù),用于傳遞類對象的引用。
示例
需要定義一個(gè)接口,繼承自Library 或StdCallLibrary
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),
CLibrary.class);
void printf(String format, Object... args);
}
搜索動(dòng)態(tài)鏈接庫路徑的順序是:先從當(dāng)前類的當(dāng)前文件夾找,如果沒有找到,再在工程當(dāng)前文件夾下面找win32/win64文件夾,找到后搜索對應(yīng)的dll文件,如果找不到再到WINDOWS下面去搜索,再找不到就會(huì)拋異常了。
JNA模擬結(jié)構(gòu)體
Structure 子類中的公共字段的順序,必須與C 語言中的結(jié)構(gòu)的順序一致。否則會(huì)報(bào)錯(cuò)!
c:
struct UserStruct{
long id;
wchar_t* name;
int age;
};
jna:
public static class UserStruct extends Structure{
public NativeLong id;
public WString name;
public int age;
public static class ByReference extends UserStruct
implements Structure.ByReference { }
public static class ByValue extends UserStruct implements
Structure.ByValue
{ }
}
public void sayUser(UserStruct.ByReference struct);
Structure 類有兩個(gè)內(nèi)部接口Structure.ByReference 和Structure.ByValue。這兩個(gè)接口僅僅是標(biāo)記,如果一個(gè)類實(shí)現(xiàn)Structure.ByReference 接口,就表示這個(gè)類代表結(jié)構(gòu)體指針。
如果一個(gè)類實(shí)現(xiàn)Structure.ByValue 接口,就表示這個(gè)類代表結(jié)構(gòu)體本身。
JNA模擬復(fù)雜結(jié)構(gòu)體
c:
struct CompanyStruct{
long id;
wchar_t* name;
UserStruct users[100];
int count;
};
jna:
public static class CompanyStruct extends Structure{
public NativeLong id;
public WString name;
public UserStruct.ByValue[] users=new UserStruct.ByValue[100];
public int count;
}
測試代碼:
CompanyStruct2.ByReference companyStruct2=new CompanyStruct2.ByReference();
companyStruct2.id=new NativeLong(2);
companyStruct2.name=new WString("Yahoo");
companyStruct2.count=10;
UserStruct.ByReference pUserStruct=new
UserStruct.ByReference();
pUserStruct.id=new NativeLong(90);
pUserStruct.age=99;
pUserStruct.name=new WString("楊致遠(yuǎn)");
// pUserStruct.write();
for(int i=0;i<companyStruct2.count;i++){
companyStruct2.users[i]=pUserStruct;
}
TestDll1.INSTANCE.sayCompany2(companyStruct2);
考察JNI 技術(shù),我們發(fā)現(xiàn)Java 調(diào)用原生函數(shù)時(shí),會(huì)把傳遞給原生函數(shù)的Java 數(shù)據(jù)固定在內(nèi)存中,這樣原生函數(shù)才可以訪問這些Java 數(shù)據(jù)。對于沒有固定住的Java 對象,GC 可以刪除它,也可以移動(dòng)它在內(nèi)存中的位置,以使堆上的內(nèi)存連續(xù)。如果原生函數(shù)訪問沒有被固定住的Java 對象,就會(huì)導(dǎo)致調(diào)用失敗。
固定住哪些java 對象,是JVM 根據(jù)原生函數(shù)調(diào)用自動(dòng)判斷的。而上面的CompanyStruct2結(jié)構(gòu)體中的一個(gè)字段是UserStruct 對象指針的數(shù)組,因此,JVM 在執(zhí)行時(shí)只是固定住了CompanyStruct2 對象的內(nèi)存,而沒有固定住users 字段引用的UserStruct 數(shù)組。因此,造成了錯(cuò)誤。
我們需要把users 字段引用的UserStruct 數(shù)組的所有成員也全部固定住,禁止GC 移動(dòng)或者刪除。
如果我們執(zhí)行了pUserStruct.write();這段代碼,那么就可以成功執(zhí)行上述代碼。
Structure 類的write()方法會(huì)把結(jié)構(gòu)體的所有字段固定住,使原生函數(shù)可以訪問。
總結(jié)
到此這篇關(guān)于java調(diào)用動(dòng)態(tài)庫dll的文章就介紹到這了,更多相關(guān)java調(diào)用動(dòng)態(tài)庫dll內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IDEA啟動(dòng)Java?Spring舊項(xiàng)目的具體配置步驟
剛剛接觸到IDEA,創(chuàng)建springboot總出現(xiàn)各種問題,這篇文章主要介紹了IDEA啟動(dòng)Java?Spring舊項(xiàng)目的具體配置步驟,文中通過圖文及實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-10-10
Unity&Springboot實(shí)現(xiàn)本地登陸驗(yàn)證
本文主要介紹了Unity&Springboot服務(wù)器/本地登陸驗(yàn)證,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07
Spring?Data?Jpa返回自定義對象的3種方法實(shí)例
在使用Spring Data Jpa框架時(shí),根據(jù)業(yè)務(wù)需求我們通常需要進(jìn)行復(fù)雜的數(shù)據(jù)庫查詢,下面這篇文章主要給大家介紹了關(guān)于Spring?Data?Jpa返回自定義對象的3種方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08
SpringCloud Config配置中心原理以及環(huán)境切換方式
這篇文章主要介紹了SpringCloud Config配置中心原理以及環(huán)境切換方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
SpringBoot中Elasticsearch的連接配置原理與使用詳解
Elasticsearch是一種開源的分布式搜索和數(shù)據(jù)分析引擎,它可用于全文搜索、結(jié)構(gòu)化搜索、分析等應(yīng)用場景,本文主要介紹了SpringBoot中Elasticsearch的連接配置原理與使用詳解,感興趣的可以了解一下2023-09-09
IDEA中Mybatis的MGB使用逆向工程配置的詳細(xì)教程
這篇文章主要介紹了IDEA中Mybatis的MGB使用逆向工程配置,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
SpringBoot如何配置數(shù)據(jù)庫主從shardingsphere
這篇文章主要介紹了SpringBoot如何配置數(shù)據(jù)庫主從shardingsphere問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04
Spring boot注解@Async線程池實(shí)例詳解
這篇文章主要介紹了Spring boot注解@Async線程池實(shí)例詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12

