java调用动态库dll/so(二)jna结构体Structure介绍和使用

我不是女神ヾ 2022-01-29 08:11 1652阅读 0赞

目录

前言

JNA数据类型与java数据类型映射关系

JNA指针介绍

怎样构建java结构体

更简单的构造结构体


  • 前言

C/C++里有结构体struct,甚至C#中也具有,然而java中却不具有结构体,当调用动态库.so和.dll时,函数接口上很多数据都是结构体,这该怎么办呢,放心jna为我们提供了Structure这个类,只要继承该类,就可实现java结构体。我们从以下几点来进行介绍。

  • JNA数据类型与java数据类型映射关系

在jna中数据类型的对应关系使用的是TypeMapper这个接口来定义jna自定义数据类型与java类型的转换。官方jna数据类型与java数据类型映射关系如下:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0ZhbnBlaV9tb3Vrb3k_size_16_color_FFFFFF_t_70

  • JNA指针介绍

以下为Structure的部分源码,其中包含两个接口,ByValue和ByReference。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0ZhbnBlaV9tb3Vrb3k_size_16_color_FFFFFF_t_70 1

ByReference具有很多实现,例如:

  1. ByteByReference
  2. DoubleByReference
  3. FloatByReference
  4. IntByReference
  5. LongByReference
  6. NativeLongByReference
  7. PointerByReference
  8. ShortByReference
  9. W32API.HANDLEByReference
  10. X11.AtomByReference
  11. X11.WindowByReference

ByValue : 结构体自身实例对象

ByReference :指针
PointerByReference :指向指针的指针

在JNA中模拟指针,最常用到的就是Pointer类和PointerByReference类。Pointer类代表指向任何东西的指针,PointerByReference类表示指向指针的指针。Pointer类更加通用,事实上PointerByReference类内部也持有Pointer类的实例。

  • 怎样构建java结构体

  1. 继承Structure,并在结构体上使用FieldOrder注解;
  2. 继承Structure,重载getFieldOrder函数。

第一种为官方使用方法,第二个方法为我自定义,二者比较,第一种使用复杂,需要在类上使用注解并设置value;第二种方法则简单,接下来我们详细描述这两种方法。

  1. package maoko.dllSolibLoad;
  2. import com.sun.jna.Structure;
  3. import com.sun.jna.Structure.FieldOrder;
  4. @FieldOrder("a,b")
  5. public class TestStructure_WithFieldOrder extends Structure {
  6. public int a;
  7. public int b;
  8. }

FieldOrder里的顺序为自己定义结构体顺序。

以下为第二种,重载:

  1. package maoko.dllSolibLoad;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. import com.sun.jna.Structure;
  5. public class TestStructure_WithOverride extends Structure {
  6. public int a;
  7. public int b;
  8. @Override
  9. protected List<String> getFieldOrder() {
  10. return Arrays.asList("a", "b");
  11. }
  12. }
  • 更简单的构造结构体

由第二种方式进行衍生,使用java反射技术将此方式变的更加的简单,具体方式为:使用一个自定义基本类即可,子类只需要定义自己的属性字段,基类定义如下:

  1. package maoko.dllSolibLoad.lib.model.struct;
  2. import java.lang.reflect.Field;
  3. import java.util.LinkedList;
  4. import java.util.List;
  5. import com.sun.jna.Pointer;
  6. import com.sun.jna.Structure;
  7. /**
  8. * java struct base
  9. *
  10. * @author fanpei
  11. *
  12. */
  13. public abstract class JavaStructBase extends Structure {
  14. /**
  15. * 默认构造函数
  16. */
  17. public JavaStructBase() {
  18. }
  19. /**
  20. * 构造函数
  21. *
  22. * @param _pointer
  23. */
  24. public JavaStructBase(Pointer _pointer) {
  25. super(_pointer);
  26. }
  27. /**
  28. * 结构体的引用
  29. *
  30. * @author maoko
  31. *
  32. */
  33. public static class ByReference extends JavaStructBase implements Structure.ByReference {
  34. }
  35. /**
  36. * 结构体对象
  37. *
  38. * @author fanpei
  39. *
  40. */
  41. public static class ByValue extends JavaStructBase implements Structure.ByValue {
  42. }
  43. @Override
  44. protected List<String> getFieldOrder() {
  45. return getStructFields();
  46. }
  47. /**
  48. * 自定义反射获取字段顺序
  49. *
  50. * @return
  51. */
  52. private List<String> getStructFields() {
  53. List<String> feilds = new LinkedList<>();
  54. Field[] declearedFeilds = this.getClass().getDeclaredFields();
  55. if (declearedFeilds != null && declearedFeilds.length > 0) {
  56. for (Field f : declearedFeilds) {
  57. feilds.add(f.getName());
  58. }
  59. }
  60. return feilds;
  61. }
  62. /**
  63. * 打印字段-测试用
  64. */
  65. @Deprecated
  66. public void printStructFeilds() {
  67. List<String> feilds = getStructFields();
  68. if (feilds == null || feilds.size() == 0)
  69. System.out.println("feilds:none");
  70. else {
  71. StringBuilder feidlSb = new StringBuilder("feilds:");
  72. for (String f : feilds) {
  73. feidlSb.append(f);
  74. feidlSb.append(",");
  75. }
  76. System.out.println(feidlSb.toString());
  77. }
  78. }
  79. }

继承类举例:

  1. package maoko.dllSolibLoad.lib.model.struct.meta;
  2. import com.sun.jna.NativeLong;
  3. import maoko.dllSolibLoad.lib.model.struct.JavaStructBase;
  4. /**
  5. * 时间信息
  6. *
  7. * @author fanpei
  8. *
  9. */
  10. public class StruFileTime extends JavaStructBase {
  11. public NativeLong dwLowDateTime;// 开始时间
  12. public NativeLong dwHighDateTime;// 结束时间
  13. }

从以上代码中可以看出JavaStructBase的getStructFields()方法实现了重载,利用反射获取子类申明的属性字段返回字段顺序list,子类则只需定义属性字段即可,且子类具有ByValue和ByReference两个静态类。

代码完整地址:https://download.csdn.net/download/fanpei_moukoy/11195072

  1. [https://github.com/maokofan/maoko.dllSoLibLoad][https_github.com_maokofan_maoko.dllSoLibLoad]

发表评论

表情:
评论列表 (有 0 条评论,1652人围观)

还没有评论,来说两句吧...

相关阅读