亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java本地方法(JNA)詳解及常見問題

 更新時(shí)間:2024年09月12日 10:06:57   作者:吳聲子夜歌  
JNA(Java?Native?Access)是一個(gè)開源Java框架,用于無需編寫JNI代碼即可動(dòng)態(tài)訪問本地系統(tǒng)庫(kù)如Windows的dll,它允許Java程序直接調(diào)用本地方法,這篇文章主要介紹了Java本地方法(JNA)詳解及常見問題,需要的朋友可以參考下

JNA

1、概述

JNA 全稱 Java Native Access,是一個(gè)建立在經(jīng)典的 JNI 技術(shù)之上的 Java 開源框架。JNA 提供一組 Java 工具類用于在運(yùn)行期動(dòng)態(tài)訪問系統(tǒng)本地庫(kù)(native library:如 Window 的 dll)而不需要編寫任何 Native/JNI 代碼。開發(fā)人員只要在一個(gè) java 接口中描述目標(biāo) native library 的函數(shù)與結(jié)構(gòu),JNA 將自動(dòng)實(shí)現(xiàn) Java 接口到native function 的映射。

官方網(wǎng)站:https://github.com/java-native-access/jna

Maven依賴:

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>5.10.0</version>
</dependency>

Java Native Access  

PackageDescription
com.sun.jnaProvides simplified native library access.

提供簡(jiǎn)化的本機(jī)庫(kù)訪問權(quán)限。

com.sun.jna.ptrProvides various native pointer-to-type ( <type> *) representations.

提供各種母語指針到類型(<類型> *)表示。

com.sun.jna.win32Provides type and function mappers required for standard APIs on the Windows platform.

提供Windows平臺(tái)上標(biāo)準(zhǔn)API所需的類型和功能映射器。

Platform Utilities  

PackageDescription
com.sun.jna.platformProvides cross-platform utilities based on platform-specific libraries.

根據(jù)特定于平臺(tái)的庫(kù)提供跨平臺(tái)實(shí)用程序。

com.sun.jna.platform.dndProvides integrated, extended drag and drop functionality, allowing ghosted drag images to be used on all platforms.

提供集成的擴(kuò)展拖放和丟棄功能,允許縮重拖動(dòng)圖像在所有平臺(tái)上使用。

Platform Specific  

PackageDescription
com.sun.jna.platform.linuxProvides common library mappings for Linux.

為L(zhǎng)inux提供公共圖書館映射。

com.sun.jna.platform.macProvides common library mappings for the OS X platform.

為OS X平臺(tái)提供公共庫(kù)映射。

com.sun.jna.platform.unixProvides common library mappings for Unix and X11-based platforms.

為基于UNIX和X11的平臺(tái)提供公共圖書館映射。

com.sun.jna.platform.unix.aixProvides common library mappings for the AIX platform.

為AIX平臺(tái)提供公共庫(kù)映射。

com.sun.jna.platform.unix.solarisProvides common library mappings for the Solaris (SunOS) platform.

為Solaris(Sunos)平臺(tái)提供公共圖書館映射。

com.sun.jna.platform.win32Provides common library mappings for the Windows platform.

為Windows平臺(tái)提供公共庫(kù)映射。

com.sun.jna.platform.win32.COMProvides common library mappings for Windows Component Object Model (COM).

為Windows組件對(duì)象模型(COM)提供公共庫(kù)映射。

com.sun.jna.platform.win32.COM.tlbProvides common library mappings for COM Type Libraries.

為COM類型庫(kù)提供公共庫(kù)映射。

com.sun.jna.platform.win32.COM.tlb.impProvides common library mappings for COM Type Library implementations.

為COM類型庫(kù)實(shí)現(xiàn)提供公共庫(kù)映射。

com.sun.jna.platform.win32.COM.utilProvides COM Utilities

提供Com Utilities.

com.sun.jna.platform.win32.COM.util.annotationProvides COM Utility annotations

提供com實(shí)用程序注釋

com.sun.jna.platform.winceProvides common library mappings for the Windows CE platform.

為Windows CE平臺(tái)提供公共庫(kù)映射。

Other Packages  

PackageDescription
com.sun.jna.internalProvides internal utilities.

提供內(nèi)部實(shí)用程序。

2、入門案例

2.1、示例一(調(diào)用系統(tǒng)共享庫(kù))

獲取mac平臺(tái)下的C共享庫(kù),然后調(diào)用printf函數(shù)打印。

public class HelloWorld {

    /**
     * 定義一個(gè)接口,默認(rèn)的是繼承Library,如果動(dòng)態(tài)鏈接庫(kù)里額函數(shù)是以stdcall方式輸出的,那么就繼承StdCallLibrary
     * 這個(gè)接口對(duì)應(yīng)一個(gè)動(dòng)態(tài)連接文件(windows:.dll, linux:.so, mac:.dylib)
     */
    public interface CLibrary extends Library {
        /**
         * 接口內(nèi)部需要一個(gè)公共靜態(tài)常量INSTANCE,通過這個(gè)常量就可以獲得這個(gè)接口的實(shí)例,從而使用接口的方法,也就是調(diào)用外部dll/so/dylib的函數(shù)
         * 該常量通過Native.load()這個(gè)API獲得
         * 第一個(gè)參數(shù)為共享庫(kù)的名稱(不帶后綴)
         * 第二個(gè)參數(shù)為本接口的Class類型,JNA通過這個(gè)這個(gè)Class類型,反射創(chuàng)建接口的實(shí)例
         * 共享庫(kù)的查找順序是:
         *  先從當(dāng)前類的當(dāng)前文件夾找,如果沒找到
         *  再?gòu)墓こ坍?dāng)前文件夾下面找,如果找不到
         *  最后在當(dāng)前平臺(tái)下面去搜索
         */
        CLibrary INSTANCE = Native.load("c", CLibrary.class);

        /**
         * 接口中只需要定義要用到的函數(shù)或者公共變量,不需要的可以不定義
         * z注意參數(shù)和返回值的類型,應(yīng)該和共享庫(kù)中的函數(shù)誒行保持一致
         */
        void printf(String format, Object... args);
    }


    public static void main(String[] args) {
        CLibrary.INSTANCE.printf("Hello,World\n");
        for (int i = 0; i < args.length; i++) {
            CLibrary.INSTANCE.printf("Argument %d:%s\n", i, args[i]);
        }
    }
}

運(yùn)行時(shí)指定參數(shù)為a b c d,運(yùn)行結(jié)果如下:

Hello,World
Argument 0:a
Argument 1:b
Argument 2:c
Argument 3:d

2.2、示例二(調(diào)用自定義共享庫(kù))

自定義一個(gè)求和C函數(shù)hello.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>

int add(int a, int b)
{
    return a + b;
}

編譯為共享庫(kù)hello.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o hello.dylib hello.c

使用JNA調(diào)用該共享庫(kù)中的add函數(shù):

public class HelloJNA {

    public interface LibraryAdd extends Library {
        //使用絕對(duì)路徑加載
        LibraryAdd LIBRARY_ADD = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/hello.dylib", LibraryAdd.class);

        int add(int a, int b);
    }

    public static void main(String[] args) {
        //調(diào)用映射的接口函數(shù)
        int add = LibraryAdd.LIBRARY_ADD.add(10, 15);
        System.out.println(add);
    }
}

輸出:

25

2、指針參數(shù)Pointer

在JAVA中都是值傳遞,但是因?yàn)槭褂肑NA框架,目標(biāo)函數(shù)是C/C++是有地址變量的,很多時(shí)候都需要將變量的結(jié)果帶回,因此,地址傳遞在JNA項(xiàng)目中幾乎是必須的。

2.1、使用場(chǎng)景

自定義求和C函數(shù),文件add.c:

//返回a+b的值
//同時(shí)c和msg通過指針參數(shù)返回
int add(int a, int b, int *c, char **msg)
{
    *c = (a + b) * 2;
    char *string = "hello world!";
    *msg = string;
    return a + b;
}

編譯為共享庫(kù)add.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o add.dylib add.c

使用JNA調(diào)用該共享庫(kù)中的add函數(shù):

public class AddTest {

    public interface LibAdd extends Library {
        LibAdd INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/add.dylib", LibAdd.class);

        int add(int a, int b, int c, String msg);
    }

    public static void main(String[] args) {
        int c = 0;
        String msg = "start";
        int add = LibAdd.INSTANCE.add(10, 15, c, msg);
        System.out.println("求和結(jié)果:" + add);
        System.out.println("c:" + c);
        System.out.println("msg:" + msg);
    }
}

結(jié)果顯而易見,無論add函數(shù)對(duì)c和msg做了何種改變,返回java中,值都不會(huì)變更。甚至?xí)驗(yàn)槲覀儗?duì)c和msg賦值導(dǎo)致C函數(shù)訪問到奇怪的地址,導(dǎo)致報(bào)錯(cuò)。

2.2、Pointer類

JNA框架提供了com.sun.jna.Pointer,指針數(shù)據(jù)類型,用于匹配轉(zhuǎn)換映射函數(shù)的指針變量。

創(chuàng)建Pointer:

//這樣的指針變量定義很像C的寫法,就是在定義的時(shí)候申請(qǐng)空間。
Pointer c = new Memory(50);
Pointer msg = new Memory(50);

Pointer映射指定的指針類型:

//映射C中的int*類型
//獲取int類型在內(nèi)存中需要的空間大小
int size = Native.getNativeSize(Integer.class); 
//為Pointer開辟int類型需要的內(nèi)存空間
Pointer int_pointer = new Memory(size);

//映射C中的double*類型
Pointer double_pointer = new Memory(Native.getNativeSize(Double.class));

Pointer設(shè)置/獲取值:

Pointer的setXxx方法提供了為各種類型設(shè)置值的方法:

第一個(gè)參數(shù)為偏移量,第二個(gè)參數(shù)為值。

//設(shè)置int
int_pointer.setInt(0, 123);
//設(shè)置double
double_pointer.setDouble(0, 22.33);

Pointer的getXxx方法提供了為各種類型獲取值的方法:

獲取單個(gè)值的參數(shù)為偏移量,獲取數(shù)組還需要傳遞一個(gè)獲取數(shù)量。

//獲取int
int anInt = int_pointer.getInt(0);
//獲取double
double aDouble = double_pointer.getDouble(0);

釋放Pointer:

Native.free(Pointer.nativeValue(c));     //手動(dòng)釋放內(nèi)存
Pointer.nativeValue(c, 0);      		//避免Memory對(duì)象被GC時(shí)重復(fù)執(zhí)行Nativ.free()方法


Native.free(Pointer.nativeValue(msg));   
Pointer.nativeValue(msg, 0);      

2.3、案例

//返回a+b的值
//同時(shí)c和msg通過指針參數(shù)返回
int add(int a, int b, int *c, char **msg)
{
    *c = (a + b) * 2;
    char *string = "hello world!";
    *msg = string;
    return a + b;
}
public class AddTest {

    public interface LibAdd extends Library {
        LibAdd INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/add.dylib", LibAdd.class);

        int add(int a, int b, Pointer c, Pointer msg);
    }

    public static void main(String[] args) {
        //int類型指針
        Pointer c = new Memory(Native.getNativeSize(Integer.class));
        //二級(jí)指針,所以嵌套Pointer
        Pointer msg = new Memory(Native.getNativeSize(Pointer.class));

        int add = LibAdd.INSTANCE.add(10, 15, c, msg);
        System.out.println("求和結(jié)果:" + add);
        System.out.println("c:" + c.getInt(0));
        //msg實(shí)際是二級(jí)指針,所以要先獲取一級(jí)指針,再獲取值
        System.out.println("msg:" + msg.getPointer(0).getString(0));

        Native.free(Pointer.nativeValue(c));   //手動(dòng)釋放內(nèi)存
        Pointer.nativeValue(c, 0);      //避免Memory對(duì)象被GC時(shí)重復(fù)執(zhí)行Native.free()方法

        Native.free(Pointer.nativeValue(msg));
        Pointer.nativeValue(msg, 0);
    }
}

輸出:

求和結(jié)果:25
c:50
msg:hello world!

3、引用對(duì)象ByReference

JNA框架提供了com.sun.jna.ptr.ByReference,引用對(duì)象類型,提供通用的“指向類型的指針”功能,通常在C代碼中用于向調(diào)用方返回值以及函數(shù)結(jié)果。

3.1、使用場(chǎng)景

在低版本的JNA中,如果C中函數(shù)執(zhí)行失敗時(shí),沒有對(duì)指針進(jìn)行處理,那么使用Pointer就會(huì)得到一個(gè)垃圾值。

C函數(shù)文件test.c:

int test_pointer(int a, int *b)
{
    if (a < 0)
    {
        //未對(duì)*b進(jìn)行處理
        return -1;
    }
    *b = a;
    return 0;
}

編譯為共享庫(kù)test.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o test.dylib test.c

使用JNA調(diào)用該共享庫(kù)中的test_pointer函數(shù):

public class PointerTest {

    public interface LibPointerTest extends Library {
        LibPointerTest INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/test.dylib", LibPointerTest.class);

        int test_pointer(int a, Pointer b);
    }

    public static void main(String[] args) {
        int a = -10;
        Pointer b = new Memory(Native.getNativeSize(Integer.class));

        int add = LibPointerTest.INSTANCE.test_pointer(a, b);
        System.out.println(add);
        System.out.println(a);
        System.out.println(b.getInt(0));
    }
}

輸出:

-1
-10
0

本文使用的為5.10版,并未發(fā)現(xiàn)垃圾值的問題。

3.2、ByReference類

ByReference提供了很多繼承類,類似Pointer的指針屬性,每種數(shù)據(jù)類型都對(duì)應(yīng)子類供使用比如int的用IntByReference,字符串的使用PointerByReference。

創(chuàng)建ByReference:

//無參構(gòu)造,默認(rèn)值為0
IntByReference intRef = new IntByReference();

//有參構(gòu)造,根據(jù)指定值創(chuàng)建
IntByReference intRef = new IntByReference(4);

設(shè)置/獲取值:

//設(shè)置
intRef.setValue(10);
//獲取
intRef.getValue();

3.3、案例

int test_pointer(int a, int *b)
{
    if (a < 0)
    {
        //未對(duì)*b進(jìn)行處理
        return -1;
    }
    *b = a;
    return 0;
}
public class PointerTest {

    public interface LibPointerTest extends Library {
        LibPointerTest INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/test.dylib", LibPointerTest.class);

        int test_pointer(int a, ByReference b);
    }

    public static void main(String[] args) {
        int a = 10;
        IntByReference b = new IntByReference();

        int add = LibPointerTest.INSTANCE.test_pointer(10, b);
        System.out.println(add);
        System.out.println(a);
        System.out.println(b.getValue());
    }
}

輸出:

0
10
10

3.4、Pointer與ByReference對(duì)比

  • Pointer和ByReference都可以在JNA項(xiàng)目中用來地址傳遞參數(shù)
  • Pointer使用方式類似C/C++需要手動(dòng)分配/回收內(nèi)存
  • ByReference使用方式就是Java語法,內(nèi)存通過垃圾回收機(jī)制自動(dòng)完成

總的來講ByReference更加方便,但是對(duì)于多層的指針引用,可能Pointer更合適處理嵌套結(jié)構(gòu)。

4、Java模擬C結(jié)構(gòu)體

4.1、使用場(chǎng)景

結(jié)構(gòu)體作為參數(shù)有兩個(gè)點(diǎn),一個(gè)是傳入,一個(gè)是返回。傳入的還分傳值和傳引用。

目標(biāo)C程序,struct.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// teacher 結(jié)構(gòu)體定義
typedef struct {
    int tea_age;
    char *tea_name;
} Teacher;

// student 結(jié)構(gòu)體定義
typedef struct {
    int stu_age;
    char *stu_name;
} Student;



Teacher stuTea(Student stu, Teacher *tea) {

    printf("stu-name=%s/n", stu.stu_name);
    printf("stu-age=%d/n", stu.stu_age);

    // 將stu復(fù)制給tea做函數(shù)返回
    Teacher teacher;
    teacher.tea_name = stu.stu_name;
    teacher.tea_age = stu.stu_age;

    tea->tea_name = strcat(tea->tea_name, "是好老師");

    return teacher;
}

函數(shù)內(nèi)部的功能也簡(jiǎn)單:

  • 打印stu的內(nèi)容【驗(yàn)證值傳遞是否正確】
  • 把stu的內(nèi)容復(fù)制給結(jié)果變量teacher,用于函數(shù)返回【驗(yàn)證是否能返回結(jié)構(gòu)體】
  • 改變傳入結(jié)構(gòu)體變量tea的值【驗(yàn)證結(jié)構(gòu)體引用傳遞是否生效】

編譯為共享庫(kù)struct.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct.dylib struct.c

JNA調(diào)用:

public class StructTest {

    //定義一個(gè)接口,描述本地庫(kù)
    public interface LibStruct extends Library {
        LibStruct INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct.dylib", LibStruct.class);

        //定義結(jié)構(gòu)體
        class TeacherStruct extends Structure {
            //結(jié)構(gòu)體參數(shù)類型及順序要嚴(yán)格按照C結(jié)構(gòu)體的類型及順序
            public int tea_age;
            public String tea_name;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends TeacherStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends TeacherStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            //重寫getFieldOrder獲取字段列表, 很重要,沒有會(huì)報(bào)錯(cuò)
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"tea_age", "tea_name"});
            }

            @Override
            public String toString() {
                return "TeacherStruct{" +
                        "tea_age=" + tea_age +
                        ", tea_name='" + tea_name + '\'' +
                        "} " + super.toString();
            }
        }

        //定義結(jié)構(gòu)體
        class StudentStruct extends Structure {
            public int stu_age;
            public String stu_name;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends StudentStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends StudentStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            //重寫getFieldOrder獲取字段列表, 很重要,沒有會(huì)報(bào)錯(cuò)
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"stu_age", "stu_name"});
            }

            @Override
            public String toString() {
                return "StudentStruct{" +
                        "stu_age=" + stu_age +
                        ", stu_name='" + stu_name + '\'' +
                        "} " + super.toString();
            }
        }

        //描述本地函數(shù)
        TeacherStruct.ByValue stuTea(StudentStruct.ByValue stu, TeacherStruct.ByReference tea);
    }

    public static void main(String[] args) {
        LibStruct.StudentStruct.ByValue stuByValue = new LibStruct.StudentStruct.ByValue();
        LibStruct.TeacherStruct.ByReference teaByReference = new LibStruct.TeacherStruct.ByReference();

        stuByValue.stu_age = 18;
        stuByValue.stu_name = "小學(xué)生";

        teaByReference.tea_age = 48;
        teaByReference.tea_name = "高級(jí)教師";

        // 調(diào)用函數(shù)之前
        System.out.println("調(diào)用函數(shù)之前teaByReference:" + teaByReference.toString());

        // 調(diào)用方法。返回結(jié)果
        LibStruct.TeacherStruct.ByValue result = LibStruct.INSTANCE.stuTea(stuByValue, teaByReference);

        // 查看傳地址的teaByReference的值是否變更
        System.out.println("調(diào)用函數(shù)之后teaByReference:" + teaByReference.toString());

        // 函數(shù)返回結(jié)果
        System.out.println("調(diào)用函數(shù)返回結(jié)果result.name:" + result.toString());

    }
}

輸出:

調(diào)用函數(shù)之前teaByReference:TeacherStruct{tea_age=48, tea_name='高級(jí)教師'} StructTest$LibStruct$TeacherStruct$ByReference(auto-allocated@0x7ffc36203c40 (16 bytes)) {
  int tea_age@0x0=0x0030
  String tea_name@0x8=高級(jí)教師
}
調(diào)用函數(shù)之后teaByReference:TeacherStruct{tea_age=48, tea_name='高級(jí)教師是好老師'} StructTest$LibStruct$TeacherStruct$ByReference(auto-allocated@0x7ffc36203c40 (16 bytes)) {
  int tea_age@0x0=0x0030
  String tea_name@0x8=高級(jí)教師是好老師
}
調(diào)用函數(shù)返回結(jié)果result.name:TeacherStruct{tea_age=18, tea_name='小學(xué)生'} StructTest$LibStruct$TeacherStruct$ByValue(auto-allocated@0x7ffc3620b480 (16 bytes)) {
  int tea_age@0x0=0x0012
  String tea_name@0x8=小學(xué)生
}
stu-name=小學(xué)生/nstu-age=18/n

4.2、Structure類

要使用 Java 類模擬 C 的結(jié)構(gòu)體,需要 Java 類繼承Structure類。

必須要注意,Structure子類中的公共字段的順序,必須與 C 語言中的結(jié)構(gòu)的順序保持一致,否則會(huì)報(bào)錯(cuò)!因?yàn)?,Java 調(diào)用動(dòng)態(tài)鏈接庫(kù)中的 C 函數(shù),實(shí)際上就是一段內(nèi)存作為函數(shù)的參數(shù)傳遞給 C 函數(shù)。動(dòng)態(tài)鏈接庫(kù)以為這個(gè)參數(shù)就是 C 語言傳過來的參數(shù)。同時(shí),C 語言的結(jié)構(gòu)體是一個(gè)嚴(yán)格的規(guī)范,它定義了內(nèi)存的次序。因此,JNA 中模擬的結(jié)構(gòu)體的變量順序絕對(duì)不能錯(cuò)。

如果一個(gè) Struct 有 2 個(gè) int 變量 int a, int b,如果 JNA 中的次序和 C 語言中的次序相反,那么不會(huì)報(bào)錯(cuò),但是數(shù)據(jù)將會(huì)被傳遞到錯(cuò)誤的字段中去。

另外,Structure類有兩個(gè)內(nèi)部接口Structure.ByReferenceStructure.ByValue。

這兩個(gè)接口僅僅是標(biāo)記:

  • 如果一個(gè)類實(shí)現(xiàn) Structure.ByReference 接口,就表示這個(gè)類代表結(jié)構(gòu)體指針。
  • 如果一個(gè)類實(shí)現(xiàn) Structure.ByValue 接口,就表示這個(gè)類代表結(jié)構(gòu)體本身。
  • 如果不實(shí)現(xiàn)這兩個(gè)接口,那么就相當(dāng)于你實(shí)現(xiàn)了 Structure.ByReference 接口。

使用這兩個(gè)接口的實(shí)現(xiàn)類,可以明確定義我們的 Structure 實(shí)例表示的是結(jié)構(gòu)體指針還是結(jié)構(gòu)體本身。

4.3、結(jié)構(gòu)體本身作為參數(shù)

struct_self_param.c

#include <stdio.h>

struct User {
    long id;
    char* name;
    int age;
};

void sayUser(struct User user)
{
    printf("id:%ld\n", user.id);
    printf("name:%s\n", user.name);
    printf("age:%d\n", user.age);
}

編譯為共享庫(kù)struct_self_param.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct_self_param.dylib struct_self_param.c

JNA調(diào)用:

public class StructSelfParamTest {

    //描述本地共享庫(kù)
    public interface LibStructSelfParam extends Library {
        LibStructSelfParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_self_param.dylib", LibStructSelfParam.class);

        //定義結(jié)構(gòu)體
        class UserStruct extends Structure {
            //公共字段的順序,必須與C語言中的結(jié)構(gòu)的順序保持一致
            public NativeLong id;
            public String name;
            public int age;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends UserStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends UserStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            // 重寫getFieldOrder獲取字段列表, 很重要,沒有會(huì)報(bào)錯(cuò)
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"id", "name", "age"});
            }
        }
        
        //描述本地函數(shù),值傳遞
        void sayUser(UserStruct.ByValue user);
    }
    
    public static void main(String[] args) {
        LibStructSelfParam.UserStruct.ByValue user = new LibStructSelfParam.UserStruct.ByValue();
        user.id = new NativeLong(10000);
        user.name = "tom";
        user.age = 18;
        LibStructSelfParam.INSTANCE.sayUser(user);
    }
}

輸出:

id:10000
name:tom
age:18

4.3、結(jié)構(gòu)體指針作為參數(shù)

struct_pointer_param.c

#include <stdio.h>

struct User {
    long id;
    char* name;
    int age;
};

void sayUser(struct User* user)
{
    printf("use strcture pointer\n");
    printf("id:%ld\n", user->id);
    printf("name:%s\n", user->name);
    printf("age:%d\n", user->age);
}

編譯為共享庫(kù)struct_pointer_param.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct_pointer_param.dylib struct_pointer_param.c

JNA調(diào)用:

public class StructPointerParamTest {
    //描述本地共享庫(kù)
    public interface LibStructPointerParam extends Library {
        LibStructPointerParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_pointer_param.dylib", LibStructPointerParam.class);

        //定義結(jié)構(gòu)體
        class UserStruct extends Structure {
            //公共字段的順序,必須與C語言中的結(jié)構(gòu)的順序保持一致
            public NativeLong id;
            public String name;
            public int age;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends StructSelfParamTest.LibStructSelfParam.UserStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends StructSelfParamTest.LibStructSelfParam.UserStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            // 重寫getFieldOrder獲取字段列表, 很重要,沒有會(huì)報(bào)錯(cuò)
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"id", "name", "age"});
            }
        }

        //描述本地函數(shù),指針傳遞
        void sayUser(UserStruct.ByReference user);
    }

    public static void main(String[] args) {
        LibStructPointerParam.UserStruct.ByReference user = new LibStructPointerParam.UserStruct.ByReference();
        user.id = new NativeLong(10000);
        user.name = "tom";
        user.age = 18;
        LibStructPointerParam.INSTANCE.sayUser(user);
    }
}

輸出:

use strcture pointer
id:10000
name:tom
age:18

4.4、嵌套結(jié)構(gòu)體本身作為參數(shù)

C 語言最復(fù)雜的數(shù)據(jù)類型就是結(jié)構(gòu)體。結(jié)構(gòu)體的內(nèi)部可以嵌套結(jié)構(gòu)體,這使它可以模擬任何類型的對(duì)象。JNA 也可以模擬這類復(fù)雜的結(jié)構(gòu)體,結(jié)構(gòu)體內(nèi)部可以包含結(jié)構(gòu)體對(duì)象指針的數(shù)組。

struct_nested_param.c

#include <stdio.h>

struct User {
    long id;
    char* name;
    int age;
};

struct Company {
    long id;
    const char* name;
    struct User users[3];
    int count;
};


void showNestedStruct(struct Company company)
{
    printf("This is nested struct.\n");
    printf("company id is:%ld\n", company.id);
    printf("company name is:%s\n", company.name);
    for (int i =0; i < 3; i++)
    {
        printf("user[%d] info of company\n", i);
        printf("user id:%ld\n", company.users[i].id);
        printf("user name:%s\n", company.users[i].name);
        printf("user age:%d\n", company.users[i].age);
    }
    printf("count %d\n", company.count);
}

編譯為共享庫(kù)struct_nested_param.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct_nested_param.dylib struct_nested_param.c

JNA調(diào)用:

public class StructNestedParamTest {

    //描述本地共享庫(kù)
    public interface LibStructNestedParam extends Library {
        LibStructNestedParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_nested_param.dylib", LibStructNestedParam.class);

        //定義User結(jié)構(gòu)體
        class UserStruct extends Structure {
            //公共字段的順序,必須與C語言中的結(jié)構(gòu)的順序保持一致
            public NativeLong id;
            public String name;
            public int age;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends UserStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends UserStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            // 重寫getFieldOrder獲取字段列表, 很重要,沒有會(huì)報(bào)錯(cuò)
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"id", "name", "age"});
            }
        }

        //定義Company結(jié)構(gòu)體
        class CompanyStruct extends Structure {
            //公共字段的順序,必須與C語言中的結(jié)構(gòu)的順序保持一致
            public NativeLong id;
            public String name;
            public UserStruct.ByValue[] users = new UserStruct.ByValue[3];
            public int count;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends CompanyStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends CompanyStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            // 重寫getFieldOrder獲取字段列表, 很重要,沒有會(huì)報(bào)錯(cuò)
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"id", "name", "users", "count"});
            }

        }

        //描述本地函數(shù),值傳遞
        void showNestedStruct(CompanyStruct.ByValue company);
    }

    public static void main(String[] args) {
        LibStructNestedParam.UserStruct.ByValue user1 = new LibStructNestedParam.UserStruct.ByValue();
        user1.id = new NativeLong(1);
        user1.name = "zhangsan";
        user1.age = 18;

        LibStructNestedParam.UserStruct.ByValue user2 = new LibStructNestedParam.UserStruct.ByValue();
        user2.id = new NativeLong(2);
        user2.name = "lisi";
        user2.age = 19;

        LibStructNestedParam.UserStruct.ByValue user3 = new LibStructNestedParam.UserStruct.ByValue();
        user3.id = new NativeLong(3);
        user3.name = "wangwu";
        user3.age = 20;

        LibStructNestedParam.CompanyStruct.ByValue company = new LibStructNestedParam.CompanyStruct.ByValue();
        company.id = new NativeLong(1000001);
        company.name = "XXXXXX有限責(zé)任公司";
        company.count = 3;
        company.users[0] = user1;
        company.users[1] = user2;
        company.users[2] = user3;

        LibStructNestedParam.INSTANCE.showNestedStruct(company);
    }
}

輸出:

This is nested struct.
company id is:1000001
company name is:XXXXXX有限責(zé)任公司
user[0] info of company
user id:1
user name:zhangsan
user age:18
user[1] info of company
user id:2
user name:lisi
user age:19
user[2] info of company
user id:3
user name:wangwu
user age:20
count 3

4.5、嵌套結(jié)構(gòu)體指針作為參數(shù)

struct_nested_pointer_param.c

#include <stdio.h>

struct User {
    long id;
    char* name;
    int age;
};

struct Company {
    long id;
    const char* name;
    struct User users[3];
    int count;
};


void showNestedStruct(struct Company* company)
{
    printf("This is nested struct.\n");
    printf("company id is:%ld\n", company->id);
    printf("company name is:%s\n", company->name);
    for (int i =0; i < 3; i++)
    {
        printf("user[%d] info of company\n", i);
        printf("user id:%ld\n", company->users[i].id);
        printf("user name:%s\n", company->users[i].name);
        printf("user age:%d\n", company->users[i].age);
    }
    printf("count %d\n", company->count);
}

編譯為共享庫(kù)struct_nested_pointer_param.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct_nested_pointer_param.dylib struct_nested_pointer_param.c

JNA調(diào)用:

public class StructNestedPointerParamTest {
    //描述本地共享庫(kù)
    public interface LibStructNestedPointerParam extends Library {
        LibStructNestedPointerParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_nested_pointer_param.dylib", LibStructNestedPointerParam.class);

        //定義User結(jié)構(gòu)體
        class UserStruct extends Structure {
            //公共字段的順序,必須與C語言中的結(jié)構(gòu)的順序保持一致
            public NativeLong id;
            public String name;
            public int age;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends UserStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends UserStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            // 重寫getFieldOrder獲取字段列表, 很重要,沒有會(huì)報(bào)錯(cuò)
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"id", "name", "age"});
            }
        }

        //定義Company結(jié)構(gòu)體
        class CompanyStruct extends Structure {
            //公共字段的順序,必須與C語言中的結(jié)構(gòu)的順序保持一致
            public NativeLong id;
            public String name;
            public UserStruct.ByValue[] users = new UserStruct.ByValue[3];
            public int count;

            // 定義值傳遞和指針傳遞類
            public static class ByReference extends CompanyStruct implements Structure.ByReference {
                //指針和引用的傳遞使用ByReference
            }
            public static class ByValue extends CompanyStruct implements Structure.ByValue {
                //拷貝參數(shù)傳遞使用ByValue
            }

            // 重寫getFieldOrder獲取字段列表, 很重要,沒有會(huì)報(bào)錯(cuò)
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"id", "name", "users", "count"});
            }

        }

        //描述本地函數(shù),指針傳遞
        void showNestedStruct(CompanyStruct.ByReference company);
    }

    public static void main(String[] args) {
        LibStructNestedPointerParam.UserStruct.ByValue user1 = new LibStructNestedPointerParam.UserStruct.ByValue();
        user1.id = new NativeLong(1);
        user1.name = "zhangsan";
        user1.age = 18;

        LibStructNestedPointerParam.UserStruct.ByValue user2 = new LibStructNestedPointerParam.UserStruct.ByValue();
        user2.id = new NativeLong(2);
        user2.name = "lisi";
        user2.age = 19;

        LibStructNestedPointerParam.UserStruct.ByValue user3 = new LibStructNestedPointerParam.UserStruct.ByValue();
        user3.id = new NativeLong(3);
        user3.name = "wangwu";
        user3.age = 20;

        LibStructNestedPointerParam.CompanyStruct.ByReference company = new LibStructNestedPointerParam.CompanyStruct.ByReference();
        company.id = new NativeLong(1000001);
        company.name = "XXXXXX有限責(zé)任公司";
        company.count = 3;
        company.users[0] = user1;
        company.users[1] = user2;
        company.users[2] = user3;

        LibStructNestedPointerParam.INSTANCE.showNestedStruct(company);
    }
}

輸出:

This is nested struct.
company id is:1000001
company name is:XXXXXX有限責(zé)任公司
user[0] info of company
user id:1
user name:zhangsan
user age:18
user[1] info of company
user id:2
user name:lisi
user age:19
user[2] info of company
user id:3
user name:wangwu
user age:20
count 3

4.6、結(jié)構(gòu)體中嵌套結(jié)構(gòu)體數(shù)組

1)、作為輸入?yún)?shù)

struct_nested_array_param.c

#include <stdio.h>

typedef struct {
    int enable;
    int x;
    int y;
    int width;
    int height;
} area_pos;

typedef struct {
    int enable;
    int x;
    int y;
} spot_pos;

typedef struct {
    int enable;
    int sta_x;
    int sta_y;
    int end_x;
    int end_y;
} line_pos;

typedef struct {
    area_pos area[2];
    spot_pos spot[2];
    line_pos line;
} image_pos;

void get_struct_array_value(image_pos *img_data){
    printf("line_pos enable:%d\n",img_data->line.enable);
    printf("line_pos sta_x:%d\n",img_data->line.sta_x);
    printf("line_pos sta_y:%d\n",img_data->line.sta_y);
    printf("line_pos end_x:%d\n",img_data->line.end_x);
    printf("line_pos end_y:%d\n",img_data->line.end_y);
    for (int i = 0; i<2;i++){
        printf("area_pos[%d] enable:%d\n",i,img_data->area[i].enable);
        printf("area_pos[%d] x:%d\n",i,img_data->area[i].x);
        printf("area_pos[%d] y:%d\n",i,img_data->area[i].y);
        printf("area_pos[%d] width:%d\n",i,img_data->area[i].width);
        printf("area_pos[%d] height:%d\n",i,img_data->area[i].height);
    }
    for (int j = 0; j < 2; j++){
        printf("spot_pos[%d] enable:%d\n",j,img_data->spot[j].enable);
        printf("spot_pos[%d] x:%d\n",j,img_data->spot[j].x);
        printf("spot_pos[%d] y:%d\n",j,img_data->spot[j].y);
    }
}

編譯為共享庫(kù)struct_nested_array_param.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct_nested_array_param.dylib struct_nested_array_param.c

JNA調(diào)用:

public class StructNestedArrayParamTest {

    public interface LibStructNestedArrayParam extends Library {
        LibStructNestedArrayParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_nested_array_param.dylib", LibStructNestedArrayParam.class);

        class AreaPos extends Structure {
            public int enable;
            public int x;
            public int y;
            public int width;
            public int height;

            public static class ByReference extends AreaPos implements Structure.ByReference { }
            public static class ByValue extends AreaPos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"enable", "x", "y", "width", "height"});
            }
        }

        class SpotPos extends Structure {
            public int enable;
            public int x;
            public int y;

            public static class ByReference extends SpotPos implements Structure.ByReference { }
            public static class ByValue extends SpotPos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"enable", "x", "y"});
            }
        }

        class LinePos extends Structure {
            public int enable;
            public int sta_x;
            public int sta_y;
            public int end_x;
            public int end_y;

            public static class ByReference extends LinePos implements Structure.ByReference { }
            public static class ByValue extends LinePos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"enable", "sta_x", "sta_y", "end_x", "end_y"});
            }
        }

        class ImagePos extends Structure {
            public AreaPos.ByValue[] area = new AreaPos.ByValue[2];
            public SpotPos.ByValue[] spot = new SpotPos.ByValue[2];
            public LinePos.ByValue line;

            public static class ByReference extends ImagePos implements Structure.ByReference { }
            public static class ByValue extends ImagePos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"area", "spot", "line"});
            }
        }

        void get_struct_array_value(ImagePos.ByReference img);
    }

    public static void main(String[] args) {
        LibStructNestedArrayParam.AreaPos.ByValue a1 = new LibStructNestedArrayParam.AreaPos.ByValue();
        a1.enable = 1;
        a1.x = 10;
        a1.y = 20;
        a1.height = 1080;
        a1.width = 1920;

        LibStructNestedArrayParam.AreaPos.ByValue a2 = new LibStructNestedArrayParam.AreaPos.ByValue();
        a1.enable = 0;
        a1.x = 20;
        a1.y = 10;
        a1.height = 1920;
        a1.width = 1080;

        LibStructNestedArrayParam.SpotPos.ByValue s1 = new LibStructNestedArrayParam.SpotPos.ByValue();
        s1.enable = 0;
        s1.x = 1;
        s1.y = 1;

        LibStructNestedArrayParam.SpotPos.ByValue s2 = new LibStructNestedArrayParam.SpotPos.ByValue();
        s1.enable = 1;
        s1.x = 2;
        s1.y = 2;

        LibStructNestedArrayParam.LinePos.ByValue line = new LibStructNestedArrayParam.LinePos.ByValue();
        line.enable = 0;
        line.end_x = 10;
        line.end_y = 20;
        line.sta_x = 30;
        line.sta_y = 40;

        LibStructNestedArrayParam.ImagePos.ByReference img = new LibStructNestedArrayParam.ImagePos.ByReference();
        img.area[0] = a1;
        img.area[1] = a2;
        img.spot[0] = s1;
        img.spot[1] = s2;
        img.line = line;

        LibStructNestedArrayParam.INSTANCE.get_struct_array_value(img);
    }
}

輸出:

line_pos enable:0
line_pos sta_x:30
line_pos sta_y:40
line_pos end_x:10
line_pos end_y:20
area_pos[0] enable:0
area_pos[0] x:20
area_pos[0] y:10
area_pos[0] width:1080
area_pos[0] height:1920
area_pos[1] enable:0
area_pos[1] x:0
area_pos[1] y:0
area_pos[1] width:0
area_pos[1] height:0
spot_pos[0] enable:1
spot_pos[0] x:2
spot_pos[0] y:2
spot_pos[1] enable:0
spot_pos[1] x:0
spot_pos[1] y:0

2)、作為輸出參數(shù)

結(jié)構(gòu)體中嵌套結(jié)構(gòu)體數(shù)組用作輸出參數(shù)時(shí),需要對(duì)結(jié)構(gòu)體數(shù)組的第一個(gè)元素賦初值。

struct_nested_array_out.c

#include <stdio.h>

typedef struct {
    int enable;
    int x;
    int y;
    int width;
    int height;
} area_pos;

typedef struct {
    int enable;
    int x;
    int y;
} spot_pos;

typedef struct {
    int enable;
    int sta_x;
    int sta_y;
    int end_x;
    int end_y;
} line_pos;

typedef struct {
    area_pos area[2];
    spot_pos spot[2];
    line_pos line;
} image_pos;

void set_struct_array_value(image_pos *img_data){
    area_pos a1,a2;
    a1.enable = 1;
    a1.x = 10;
    a1.y = 20;
    a1.height = 1090;
    a1.width = 1920;
    a2.enable = 0;
    a2.x = 20;
    a2.y = 10;
    a2.height = 1920;
    a2.width = 1080;
    
    spot_pos s1,s2;
    s1.enable = 0;
    s1.x = 1;
    s1.y = 1;
    s2.enable = 1;
    s2.x = 2;
    s2.y = 2;
    
    line_pos l;
    l.enable = 0;
    l.end_x = 10;
    l.end_y = 20;
    l.sta_x = 30;
    l.sta_y = 40; 

	img_data->area[0] = a1;
    img_data->area[1] = a2;
    img_data->spot[0] = s1;
    img_data->spot[1] = s2;
    img_data->line = l;
}

編譯為共享庫(kù)struct_nested_array_out.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct_nested_array_out.dylib struct_nested_array_out.c

JNA調(diào)用:

public class StructNestedArrayOutTest {

    public interface LibStructNestedArrayOut extends Library {
        LibStructNestedArrayOut INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_nested_array_out.dylib", LibStructNestedArrayOut.class);

        class AreaPos extends Structure {
            public int enable;
            public int x;
            public int y;
            public int width;
            public int height;

            public static class ByReference extends AreaPos implements Structure.ByReference { }
            public static class ByValue extends AreaPos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"enable", "x", "y", "width", "height"});
            }

            @Override
            public String toString() {
                return "AreaPos{" +
                        "enable=" + enable +
                        ", x=" + x +
                        ", y=" + y +
                        ", width=" + width +
                        ", height=" + height +
                        "} " + super.toString();
            }
        }

        class SpotPos extends Structure {
            public int enable;
            public int x;
            public int y;

            public static class ByReference extends SpotPos implements Structure.ByReference { }
            public static class ByValue extends SpotPos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"enable", "x", "y"});
            }

            @Override
            public String toString() {
                return "SpotPos{" +
                        "enable=" + enable +
                        ", x=" + x +
                        ", y=" + y +
                        "} " + super.toString();
            }
        }

        class LinePos extends Structure {
            public int enable;
            public int sta_x;
            public int sta_y;
            public int end_x;
            public int end_y;

            public static class ByReference extends LinePos implements Structure.ByReference { }
            public static class ByValue extends LinePos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"enable", "sta_x", "sta_y", "end_x", "end_y"});
            }

            @Override
            public String toString() {
                return "LinePos{" +
                        "enable=" + enable +
                        ", sta_x=" + sta_x +
                        ", sta_y=" + sta_y +
                        ", end_x=" + end_x +
                        ", end_y=" + end_y +
                        "} " + super.toString();
            }
        }

        class ImagePos extends Structure {
            public AreaPos.ByValue[] area = new AreaPos.ByValue[2];
            public SpotPos.ByValue[] spot = new SpotPos.ByValue[2];
            public LinePos.ByValue line;

            public static class ByReference extends ImagePos implements Structure.ByReference { }
            public static class ByValue extends ImagePos implements Structure.ByValue { }

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"area", "spot", "line"});
            }
        }

        void set_struct_array_value(ImagePos.ByReference img);
    }

    public static void main(String[] args) {
        LibStructNestedArrayOut.ImagePos.ByReference img = new LibStructNestedArrayOut.ImagePos.ByReference();
        // img.area[0] = new LibStructNestedArrayOut.AreaPos.ByValue();
        // img.spot[0] = new LibStructNestedArrayOut.SpotPos.ByValue();
        LibStructNestedArrayOut.INSTANCE.set_struct_array_value(img);
        for (int i = 0; i < 2; i++)
            System.out.println(img.area[i]);
        for (int i = 0; i < 2; i++)
            System.out.println(img.spot[i]);
        System.out.println(img.line);
    }
}

如果未對(duì)數(shù)組第一項(xiàng)賦值,會(huì)報(bào)java.lang.IndexOutOfBoundsException

Exception in thread "main" java.lang.IndexOutOfBoundsException: Bounds exceeds available space : size=20, offset=40

所以一定要對(duì)輸出參數(shù)中的數(shù)組第一項(xiàng)賦值:

public static void main(String[] args) {
    LibStructNestedArrayOut.ImagePos.ByReference img = new LibStructNestedArrayOut.ImagePos.ByReference();
    img.area[0] = new LibStructNestedArrayOut.AreaPos.ByValue();
    img.spot[0] = new LibStructNestedArrayOut.SpotPos.ByValue();
    LibStructNestedArrayOut.INSTANCE.set_struct_array_value(img);
    for (int i = 0; i < 2; i++)
        System.out.println(img.area[i]);
    for (int i = 0; i < 2; i++)
        System.out.println(img.spot[i]);
    System.out.println(img.line);
}

輸出:

AreaPos{enable=1, x=10, y=20, width=1920, height=1090} StructNestedArrayOutTest$LibStructNestedArrayOut$AreaPos$ByValue(allocated@0x7fb3b0d1bd10 (20 bytes) (shared from auto-allocated@0x7fb3b0d1bd10 (84 bytes))) {
  int enable@0x0=0x0001
  int x@0x4=0x000A
  int y@0x8=0x0014
  int width@0xC=0x0780
  int height@0x10=0x0442
}
AreaPos{enable=0, x=20, y=10, width=1080, height=1920} StructNestedArrayOutTest$LibStructNestedArrayOut$AreaPos$ByValue(allocated@0x7fb3b0d1bd24 (20 bytes) (shared from auto-allocated@0x7fb3b0d1bd10 (84 bytes))) {
  int enable@0x0=0x0000
  int x@0x4=0x0014
  int y@0x8=0x000A
  int width@0xC=0x0438
  int height@0x10=0x0780
}
SpotPos{enable=0, x=1, y=1} StructNestedArrayOutTest$LibStructNestedArrayOut$SpotPos$ByValue(allocated@0x7fb3b0d1bd38 (12 bytes) (shared from auto-allocated@0x7fb3b0d1bd10 (84 bytes))) {
  int enable@0x0=0x0000
  int x@0x4=0x0001
  int y@0x8=0x0001
}
SpotPos{enable=1, x=2, y=2} StructNestedArrayOutTest$LibStructNestedArrayOut$SpotPos$ByValue(allocated@0x7fb3b0d1bd44 (12 bytes) (shared from auto-allocated@0x7fb3b0d1bd10 (84 bytes))) {
  int enable@0x0=0x0001
  int x@0x4=0x0002
  int y@0x8=0x0002
}
LinePos{enable=0, sta_x=30, sta_y=40, end_x=10, end_y=20} StructNestedArrayOutTest$LibStructNestedArrayOut$LinePos$ByValue(allocated@0x7fb3b0d1bd50 (20 bytes) (shared from auto-allocated@0x7fb3b0d1bd10 (84 bytes))) {
  int enable@0x0=0x0000
  int sta_x@0x4=0x001E
  int sta_y@0x8=0x0028
  int end_x@0xC=0x000A
  int end_y@0x10=0x0014
}

4.7、結(jié)構(gòu)體數(shù)組作為參數(shù)

文件struct_array_param.c

#include <stdio.h>
#include <string.h>

typedef struct {
    int age;
    char name[20];
} Person;


int changeObjs(Person per[], int size)
{
    if (size <= 0) 
    {
        return -1;
    }
    for (int i = 0; i < size; i++)
    {
        per[i].age *= 10;
        strcpy(per[i].name, "wokettas");
    }
    for (int k = 0; k < size; k++)
    {
        printf("person[%d] age:%d\n", k, per[k].age);
        printf("person[%d] name:%s\n", k, per[k].name);
    }
    return 0;
}

編譯為共享庫(kù)struct_array_param.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o struct_array_param.dylib struct_array_param.c

1)、錯(cuò)誤的調(diào)用一

public class StructArrayParamTest {

    public interface LibStructArrayParam extends Library {
        LibStructArrayParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_array_param.dylib", LibStructArrayParam.class);

        class Person extends Structure {
            public int age;
            public byte[] name = new byte[20];

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"age", "name"});
            }

            //值傳遞
            public static class ByValue extends Person implements Structure.ByValue { }

        }

        //描述函數(shù)
        int changeObjs(Person.ByValue[] per, int size);
    }

    public static void main(String[] args) {
        LibStructArrayParam.Person.ByValue[] per = new LibStructArrayParam.Person.ByValue[2];
        LibStructArrayParam.Person.ByValue p1 = new LibStructArrayParam.Person.ByValue();
        LibStructArrayParam.Person.ByValue p2 = new LibStructArrayParam.Person.ByValue();
        p1.age = 1;
        p1.name = Arrays.copyOf("tom".getBytes(), 20);
        p2.age = 2;
        p2.name = Arrays.copyOf("jerry".getBytes(), 20);
        per[0] = p1;
        per[1] = p2;

        LibStructArrayParam.INSTANCE.changeObjs(per, 2);
    }
}

如果在 Java 接口聲明中錯(cuò)誤把參數(shù)類型寫成Person.ByValue,會(huì)報(bào)java.lang.IndexOutOfBoundsException。將參數(shù)類型改為結(jié)構(gòu)體本身即可,即不帶 ByReference 或 ByValue。結(jié)構(gòu)體數(shù)組做參數(shù)時(shí), 要區(qū)別于非數(shù)組的 ByReference 和 ByValue。

2)、錯(cuò)誤的調(diào)用二

public class StructArrayParamTest {

    public interface LibStructArrayParam extends Library {
        LibStructArrayParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_array_param.dylib", LibStructArrayParam.class);

        class Person extends Structure {
            public int age;
            public byte[] name = new byte[20];

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"age", "name"});
            }
        }

        //描述函數(shù)
        int changeObjs(Person[] per, int size);
    }

    public static void main(String[] args) {
        LibStructArrayParam.Person[] per = new LibStructArrayParam.Person[2];
        LibStructArrayParam.Person p1 = new LibStructArrayParam.Person();
        LibStructArrayParam.Person p2 = new LibStructArrayParam.Person();
        p1.age = 1;
        p1.name = Arrays.copyOf("tom".getBytes(), 20);
        p2.age = 2;
        p2.name = Arrays.copyOf("jerry".getBytes(), 20);
        per[0] = p1;
        per[1] = p2;

        LibStructArrayParam.INSTANCE.changeObjs(per, 2);
    }
}

會(huì)報(bào)錯(cuò)Exception in thread "main" java.lang.IllegalArgumentException: Structure array elements must use contiguous memory (bad backing address at Structure array index 1)

結(jié)構(gòu)體數(shù)組必須使用連續(xù)的內(nèi)存區(qū)域。p1,p2 都是 new 出來的對(duì)象,不可能連續(xù),用傳統(tǒng)方式初始化數(shù)組不能解決。

應(yīng)使用JNA提供的toArray方法:

public Structure[] toArray(int size);

3)、正確的調(diào)用

public class StructArrayParamTest {

    public interface LibStructArrayParam extends Library {
        LibStructArrayParam INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/struct_array_param.dylib", LibStructArrayParam.class);

        class Person extends Structure {
            public int age;
            public byte[] name = new byte[20];

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[]{"age", "name"});
            }
        }

        //描述函數(shù)
        int changeObjs(Person[] per, int size);
    }

    public static void main(String[] args) {
        LibStructArrayParam.Person per = new LibStructArrayParam.Person();
        LibStructArrayParam.Person[] pers = (LibStructArrayParam.Person[]) per.toArray(2);
        pers[0].age = 1;
        pers[0].name = Arrays.copyOf("tom".getBytes(), 20);
        pers[1].age = 2;
        pers[1].name = Arrays.copyOf("jerry".getBytes(), 20);

        LibStructArrayParam.INSTANCE.changeObjs(pers, 2);
    }
}

輸出:

person[0] age:10
person[0] name:wokettas
person[1] age:20
person[1] name:wokettas

5、常見問題

5.1、Java 類的字段聲明必須與重寫方法保持一致

類中變量名要和重寫后的方法中的保持一致(名稱不一致,變量個(gè)數(shù)不一致都會(huì)失敗),否則編譯不通過。

Java 中模擬結(jié)構(gòu)體時(shí),類名可以和 C 的結(jié)構(gòu)體名稱不同,只需要 Java 類的各個(gè)字段名稱、 各字段順序?qū)?yīng)結(jié)構(gòu)體中的字段即可。

5.2、Java映射C數(shù)組亂碼問題

文件array_param.c

#include <stdio.h>
#include <string.h>

typedef struct {
    int enable;
    char static_ip[20];
    char netmask[20];
    char gateway[20];
    char dns1[20];
    char dns2[20];
}network_eth;

int sdk_set_network_eth(const char *ip, network_eth *network_param)
{
    if (strlen(ip) == 0 || network_param == NULL)
    { 
        printf("sdk_set_network_eth param error!\n"); 
        return -1;
    }
    printf("ip:%s\n",ip);
    printf("network_eth enable:%d\n",network_param->enable); 
    printf("network_eth static_ip:%s\n",network_param->static_ip); 
    printf("network_eth netmask:%s\n",network_param->netmask); 
    printf("network_eth gateway:%s\n",network_param->gateway); 
    printf("network_eth dns1:%s\n",network_param->dns1); 
    printf("network_eth dns2:%s\n",network_param->dns2);
    return 0;
}

編譯為共享庫(kù)array_param.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o array_param.dylib array_param.c

JNA調(diào)用:

public class CharArrayTest {

    public interface LibCharArray extends Library {
        LibCharArray INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/array_param.dylib", LibCharArray.class);


        class NetWorkEth extends Structure {
            public int enable;
            public byte[] static_ip = new byte[20];
            public byte[] netmask = new byte[20];
            public byte[] gateway = new byte[20];
            public byte[] dns1 = new byte[20];
            public byte[] dns2 = new byte[20];

            public static class ByReference extends NetWorkEth implements Structure.ByReference{}
            public static class ByValue extends NetWorkEth implements Structure.ByValue{}

            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(new String[] {"enable","static_ip","netmask","gateway","dns1","dns2"});
            }
        }

        int sdk_set_network_eth(byte[] ip, NetWorkEth.ByReference netWork);
    }

    public static void main(String[] args) {
        String ip = "127.0.0.1";
        LibCharArray.NetWorkEth.ByReference netWorkEth = new LibCharArray.NetWorkEth.ByReference();
        netWorkEth.enable = 1;
        netWorkEth.static_ip = "10.20.6.10".getBytes();
        netWorkEth.netmask = "255.255.255.0".getBytes();
        netWorkEth.gateway = "192.168.122.134".getBytes();
        netWorkEth.dns1 = "114.114.114.114".getBytes();
        netWorkEth.dns2 = "8.8.8.8".getBytes();

        int res = LibCharArray.INSTANCE.sdk_set_network_eth(ip.getBytes(), netWorkEth);
        System.out.println(res);

    }

輸出:

0
ip:127.0.0.1
network_eth enable:1
network_eth static_ip:10.20.6.10255.255.255.0192.168.122.134114.114.114.1148.8.8.8127.0.0.1
network_eth netmask:5.0192.168.122.134114.114.114.1148.8.8.8127.0.0.1
network_eth gateway:4.114.114.1148.8.8.8127.0.0.1
network_eth dns1:127.0.0.1
network_eth dns2:??#mRealVarArgsCheckerlang/O

輸出亂碼!因?yàn)镃/C++的數(shù)組類型在內(nèi)存中是連續(xù)存儲(chǔ)的,而Java的數(shù)組不一定是連續(xù)的。對(duì)C中的char數(shù)組類型賦值時(shí),不能直接給數(shù)組賦值,要使用Arrays.copyOf(String.getBytes(), 20)賦值,數(shù)組長(zhǎng)度和C結(jié)構(gòu)體中聲明的長(zhǎng)度保持一致。

在某些情況下,雖然使用 String.getBytes()轉(zhuǎn)換也能成功,但大多數(shù)情況下,使用該方法會(huì)出 現(xiàn)亂碼,不建議使用 String.getBytes()。

public static void main(String[] args) {
    String ip = "127.0.0.1";
    byte[] ipArr = Arrays.copyOf(ip.getBytes(), 20);
    LibCharArray.NetWorkEth.ByReference netWorkEth = new LibCharArray.NetWorkEth.ByReference();
    netWorkEth.enable = 1;
    netWorkEth.static_ip = Arrays.copyOf("10.20.6.10".getBytes(), 20);
    netWorkEth.netmask = Arrays.copyOf("255.255.255.0".getBytes(), 20);
    netWorkEth.gateway = Arrays.copyOf("192.168.122.134".getBytes(), 20);
    netWorkEth.dns1 = Arrays.copyOf("114.114.114.114".getBytes(), 20);
    netWorkEth.dns2 = Arrays.copyOf("8.8.8.8".getBytes(), 20);

    int res = LibCharArray.INSTANCE.sdk_set_network_eth(ipArr, netWorkEth);
    System.out.println(res);
}

輸出:

0
ip:127.0.0.1
network_eth enable:1
network_eth static_ip:10.20.6.10
network_eth netmask:255.255.255.0
network_eth gateway:192.168.122.134
network_eth dns1:114.114.114.114
network_eth dns2:8.8.8.8

創(chuàng)建結(jié)構(gòu)體數(shù)組應(yīng)該使用 JNA 的 toArray()方法,而不是 Java 常規(guī)創(chuàng)建數(shù)組的方法,因?yàn)閮?nèi) 存空間在 java 中是不連續(xù)的,jna 定義數(shù)組是需要使用 toArray 方法,這樣實(shí)例化出來的數(shù) 組內(nèi)存空間是連續(xù)的。

5.3、Java 接收 C 函數(shù)返回類型為 char*

JNA 使用 String 無法直接接收 C 函數(shù)返回類型為 char*的值,必須要用 Pointer 進(jìn)行接收。

當(dāng) C 函數(shù)的參數(shù)為 char*、const char*用做輸入時(shí),JNA 可以使用 String 類型進(jìn)行傳 參,此時(shí)可以正常調(diào)用 C 函數(shù);但當(dāng)C函數(shù)的參數(shù)類型為char*且用作輸出時(shí),使用 String 類型無法正常接收,必須使用 Pointer 進(jìn)行處理。

文件char_out.c

#include <stdio.h>
#include <string.h>

void append_str(char* str, char* append)
{
    printf("str:%s\n", str);
    printf("append:%s\n", append);
    int length = strlen(str);
    char* p = str;
    for(int i = 0; i < length; i++)
    {
        p++;
    }
    strcpy(p, append);
}

編譯為共享庫(kù)char_out.dylib:

gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -dynamiclib -o char_out.dylib char_out.c

JNA調(diào)用,使用Pointer接收char*返回值:

public class CharOutTest {

    public interface LibCharOut extends Library {
        LibCharOut INSTANCE = Native.load("/Users/acton_zhang/J2EE/MavenWorkSpace/java_safe_demo/src/main/java/pers/zhang/jna/char_out.dylib", LibCharOut.class);

        void append_str(Pointer str, String append);
    }

    public static void main(String[] args) {
        Pointer str = new Memory(40);
        str.setString(0, "hello");
        String append = " world";
        LibCharOut.INSTANCE.append_str(str, append);
        System.out.println(str.getString(0));
    }
}

輸出:

hello world
str:hello
append: world

通過 Java 獲取 char * 字符串,必須要通過 Java 傳入一個(gè) com.sun.jna.Pointer 指針變量,然后在 DLL 中將值賦給此指針變量,然后通過此指針變量獲取值。

5.4、動(dòng)態(tài)庫(kù)和 jdk 的位數(shù)必須匹配

64 位的 jdk 只能調(diào)用 64 位的 dll,32 位也一樣。如果使用的 jdk 和 dll 位數(shù)不同,會(huì)報(bào) Unable to load DLL 'xxx.dll': 找不到指定的模塊或者java.lang.UnsatisfiedLinkError: %1 不是有效的 Win32 應(yīng)用程序。

5.5、動(dòng)態(tài)庫(kù)版本必須和系統(tǒng)類型匹配

  • windows:后綴名為.dll
  • linux:后綴名為.so
  • mac:后綴名為.dylib

總結(jié) 

到此這篇關(guān)于Java本地方法(JNA)詳解及常見問題的文章就介紹到這了,更多相關(guān)Java本地方法JNA內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java根據(jù)控制臺(tái)實(shí)現(xiàn)定位異常

    Java根據(jù)控制臺(tái)實(shí)現(xiàn)定位異常

    這篇文章主要介紹了Java根據(jù)控制臺(tái)定位異常,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • 修改SpringBoot 中MyBatis的mapper.xml文件位置的過程詳解

    修改SpringBoot 中MyBatis的mapper.xml文件位置的過程詳解

    由于MyBatis默認(rèn)的mapper.xml的掃描位置是resource文件下,但是不可能整個(gè)項(xiàng)目的mapper.xml文件都放在resource下,如果文件較少還行,但是如果文件比較多,太麻煩了,所以本文給大家介紹了修改SpringBoot 中MyBatis的mapper.xml文件位置的過程,需要的朋友可以參考下
    2024-08-08
  • java.exe和javaw.exe的區(qū)別及使用方法

    java.exe和javaw.exe的區(qū)別及使用方法

    這篇文章主要介紹了java.exe和javaw.exe的區(qū)別及使用方法,需要的朋友可以參考下
    2014-04-04
  • 關(guān)于IDEA配置文件字符集的問題

    關(guān)于IDEA配置文件字符集的問題

    這篇文章主要介紹了關(guān)于IDEA配置文件字符集的問題,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • Mac?M1安裝JDK的實(shí)戰(zhàn)避坑指南

    Mac?M1安裝JDK的實(shí)戰(zhàn)避坑指南

    這篇文章主要給大家介紹了關(guān)于Mac?M1安裝JDK避坑的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-02-02
  • 微服務(wù)Redis-Session共享登錄狀態(tài)的過程詳解

    微服務(wù)Redis-Session共享登錄狀態(tài)的過程詳解

    這篇文章主要介紹了微服務(wù)Redis-Session共享登錄狀態(tài),本文采取Spring security做登錄校驗(yàn),用redis做session共享,實(shí)現(xiàn)單服務(wù)登錄可靠性,微服務(wù)之間調(diào)用的可靠性與通用性,需要的朋友可以參考下
    2023-12-12
  • 一文帶你深入剖析Java線程池的前世今生

    一文帶你深入剖析Java線程池的前世今生

    這篇文章主要帶大家介紹了深入剖析一下Java線程池的前世今生,了解線程池的原理以及為什么需要線程池。文中的示例代碼講解詳細(xì),需要的可以參考一下
    2022-10-10
  • SpringBoot實(shí)現(xiàn)發(fā)送QQ郵件的示例代碼

    SpringBoot實(shí)現(xiàn)發(fā)送QQ郵件的示例代碼

    這篇文章主要介紹了SpringBoot如何實(shí)現(xiàn)發(fā)送QQ郵件功能,本文通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • spring boot 配置動(dòng)態(tài)刷新詳解

    spring boot 配置動(dòng)態(tài)刷新詳解

    這篇文章主要介紹了spring boot 配置動(dòng)態(tài)刷新實(shí)現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-09-09
  • SpringBoot中使用異步調(diào)度程序的高級(jí)方法

    SpringBoot中使用異步調(diào)度程序的高級(jí)方法

    本文主要介紹了SpringBoot中使用異步調(diào)度程序的高級(jí)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07

最新評(píng)論