Java通过JNA调用系统API,java jfinal_1

  Java通过JNA调用系统API,java jfinal

  00-1010 native中的structStructure介绍一种特殊类型的结构结构数组作为参数结构数组作为返回值。给出了可变字段结构中只读字段的总结。

  00-1010之前,我们讨论了JNA中JAVA代码和本机代码之间的映射。虽然JAVA和native中的类型可以通过TypeMapper进行映射,但是native中的数据类型都是基本类型。如果native中的数据类型是复杂的struct类型,如何映射呢?

  别担心,JNA提供了结构类来帮助我们完成这些映射过程。

  00-1010什么时候使用struct?一般当我们需要自定义一个数据类的时候,一般来说,我们需要在JAVA中定义一个类(在JDK17中,可以用更简单的记录来代替),但是为一个数据结构定义一个类显然是臃肿的,所以在原生语言中,有一些更简单的数据结构叫做struct。

  我们先看一个struct的定义:

  typedef struct _Point { int x,y;}点;在上面的代码中,我们在struct数据类下定义了一个指针,其中我们定义了int的x和y值来表示Point的水平和垂直坐标。

  Struct有两种用法,一种是值传递,一种是引用传递。让我们先来看看这两种情况是如何在本机方法中使用的:

  引用传递:

  Point* translate(Point* pt,int dx,int dy);值传递:

  点平移(Point pt,int dx,int dy);

  00-1010那么我们应该如何映射原生方法中struct数据类型的用法呢?JNA给我们提供了结构课。

  默认情况下,如果Structure用作参数或返回值,它映射struct *;如果它表示结构中的字段,则它映射结构。

  当然,你也可以强制使用结构。通过引用或结构。ByValue指示是传递引用还是值。

  我们来看看上面native的例子。如果您使用JNA的结构进行映射,应该如何实现:

  指针映射:

  类点扩展结构{ public int x,y;}Point translate(点pt,int x,int y);Point pt=new Point();积分结果=translate(pt,100,100);传值映射:

  类点扩展结构{公共静态类ByValue扩展点实现结构。ByValue { } public int x,y;}点。按值翻译(点。ByValue pt,int x,int y);点。ByValue pt=新点。by value();积分结果=translate(pt,100,100);结构内部提供了两个接口,即ByValue和ByReference:

  公共抽象类结构{按值公共接口{}按引用公共接口{}要使用它,需要继承相应的接口。

  00-1010除了上面提到的struct,struct还有其他更复杂的用法。

  

目录

首先来看一下结构体数组作为参数的情况:

 

  :java;">void get_devices(struct Device[], int size);对应结构体数组,可以直接使用JNA中对应的Structure数组来进行映射:

  

int size = ...Device[] devices = new Device[size];lib.get_devices(devices, devices.length);

 

  

结构体数组作为返回值

如果native方法返回的是一个指向结构体的指针,其本质上是一个结构体数组,我们应该怎么处理呢?

 

  先看一下native方法的定义:

  

struct Display* get_displays(int* pcount);void free_displays(struct Display* displays);

get_displays方法返回的是一个指向结构体数组的指针,pcount是结构体的个数。

 

  对应的JAVA代码如下:

  

Display get_displays(IntByReference pcount);void free_displays(Display[] displays);

对于第一个方法来说,我们只返回了一个Display,但是可以通过Structure.toArray(int) 方法将其转换成为结构体数组。传入到第二个方法中,具体的调用方式如下:

 

  

IntByReference pcount = new IntByReference();Display d = lib.get_displays(pcount);Display[] displays = (Display[])d.toArray(pcount.getValue());...lib.free_displays(displays);

 

  

结构体中的结构体

结构体中也可以嵌入结构体,先看下native方法的定义:

 

  

typedef struct _Point { int x, y;} Point;typedef struct _Line { Point start; Point end;} Line;

对应的JAVA代码如下:

 

  

class Point extends Structure { public int x, y;}class Line extends Structure { public Point start; public Point end;}

如果是下面的结构体中的指向结构体的指针:

 

  

typedef struct _Line2 { Point* p1; Point* p2;} Line2;

那么对应的代码如下:

 

  

class Point extends Structure { public static class ByReference extends Point implements Structure.ByReference { } public int x, y;}class Line2 extends Structure { public Point.ByReference p1; public Point.ByReference p2;}

或者直接使用Pointer作为Structure的属性值:

 

  

class Line2 extends Structure { public Pointer p1; public Pointer p2;}Line2 line2;Point p1, p2;...line2.p1 = p1.getPointer();line2.p2 = p2.getPointer();

 

  

结构体中的数组

如果结构体中带有固定大小的数组:

 

  

typedef struct _Buffer { char buf1[32]; char buf2[1024];} Buffer;

那么我们在JAVA中需要指定数据的大小:

 

  

class Buffer extends Structure { public byte[] buf1 = new byte[32]; public byte[] buf2 = new byte[1024];}

如果结构体中是动态大小的数组:

 

  

typedef struct _Header { int flags; int buf_length; char buffer[1];} Header;

那么我们需要在JAVA的结构体中定义一个构造函数,传入bufferSize的大小,并分配对应的内存空间:

 

  

 

  

结构体中的可变字段

默认情况下结构体中的内容和native memory的内容是一致的。JNA会在函数调用之前将Structure的内容写入到native memory中,并且在函数调用之后,将 native memory中的内容回写到Structure中。

 

  默认情况下是将结构体中的所有字段都进行写入和写出。但是在某些情况下,我们希望某些字段不进行自动更新。这个时候就可以使用volatile关键字,如下所示:

  

class Data extends com.sun.jna.Structure { public volatile int refCount; public int value;}...Data data = new Data();

当然,你也可以强制使用Structure.writeField(String)来将字段信息写入内存中,或者使用Structure.read() 来更新整个结构体的信息或者使用data.readField(refCount)来更新具体字段信息。

 

  

 

  

结构体中的只读字段

如果不想从JAVA代码中对Structure的内容进行修改,则可以将对应的字段标记为final。在这种情况下,虽然JAVA代码不能直接对其进行修改,但是仍然可以调用read方法从native memory中读取对应的内容并覆盖Structure中对应的值。

 

  来看下JAVA中如何使用final字段:

  

class ReadOnly extends com.sun.jna.Structure { public final int refCount; { // 初始化 refCount = -1; // 从内存中读取数据 read(); }}
注意所有的字段的初始化都应该在构造函数或者静态方法块中进行。

 

  

 

  

总结

结构体是native方法中经常会使用到的一种数据类型,JNA中对其进行映射的方法是我们要掌握的。

 

  到此这篇关于java高级用法之JNA中的Structure的文章就介绍到这了,更多相关java 中的Structure内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: