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

 

目录

前言

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

JNA指针介绍

怎样构建java结构体

更简单的构造结构体


  • 前言

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

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

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

java调用动态库dll/so(二)jna结构体Structure介绍和使用_第1张图片

  • JNA指针介绍

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

java调用动态库dll/so(二)jna结构体Structure介绍和使用_第2张图片

ByReference具有很多实现,例如:

ByteByReference
DoubleByReference
FloatByReference
IntByReference
LongByReference
NativeLongByReference
PointerByReference
ShortByReference
W32API.HANDLEByReference
X11.AtomByReference
X11.WindowByReference

ByValue                     :   结构体自身实例对象

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

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

  • 怎样构建java结构体

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

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

package maoko.dllSolibLoad;

import com.sun.jna.Structure;
import com.sun.jna.Structure.FieldOrder;

@FieldOrder("a,b")
public class TestStructure_WithFieldOrder extends Structure {
	public int a;
	public int b;
}

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

以下为第二种,重载:

package maoko.dllSolibLoad;

import java.util.Arrays;
import java.util.List;

import com.sun.jna.Structure;

public class TestStructure_WithOverride extends Structure {

	public int a;
	public int b;

	@Override
	protected List getFieldOrder() {
		return Arrays.asList("a", "b");
	}
}
  • 更简单的构造结构体

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

package maoko.dllSolibLoad.lib.model.struct;

import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;

import com.sun.jna.Pointer;
import com.sun.jna.Structure;

/**
 * java struct base
 * 
 * @author fanpei
 *
 */
public abstract class JavaStructBase extends Structure {

	/**
	 * 默认构造函数
	 */
	public JavaStructBase() {
	}

	/**
	 * 构造函数
	 * 
	 * @param _pointer
	 */
	public JavaStructBase(Pointer _pointer) {
		super(_pointer);
	}

	/**
	 * 结构体的引用
	 * 
	 * @author maoko
	 *
	 */
	public static class ByReference extends JavaStructBase implements Structure.ByReference {
	}

	/**
	 * 结构体对象
	 * 
	 * @author fanpei
	 *
	 */
	public static class ByValue extends JavaStructBase implements Structure.ByValue {
	}

	@Override
	protected List getFieldOrder() {
		return getStructFields();
	}

	/**
	 * 自定义反射获取字段顺序
	 * 
	 * @return
	 */
	private List getStructFields() {
		List feilds = new LinkedList<>();
		Field[] declearedFeilds = this.getClass().getDeclaredFields();
		if (declearedFeilds != null && declearedFeilds.length > 0) {
			for (Field f : declearedFeilds) {
				feilds.add(f.getName());
			}
		}
		return feilds;
	}

	/**
	 * 打印字段-测试用
	 */
	@Deprecated
	public void printStructFeilds() {
		List feilds = getStructFields();
		if (feilds == null || feilds.size() == 0)
			System.out.println("feilds:none");
		else {
			StringBuilder feidlSb = new StringBuilder("feilds:");
			for (String f : feilds) {
				feidlSb.append(f);
				feidlSb.append(",");
			}
			System.out.println(feidlSb.toString());
		}
	}

}

继承类举例:

package maoko.dllSolibLoad.lib.model.struct.meta;

import com.sun.jna.NativeLong;

import maoko.dllSolibLoad.lib.model.struct.JavaStructBase;

/**
 * 时间信息
 * 
 * @author fanpei
 *
 */
public class StruFileTime extends JavaStructBase {
	public NativeLong dwLowDateTime;// 开始时间
	public NativeLong dwHighDateTime;// 结束时间
}

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

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

                         https://github.com/maokofan/maoko.dllSoLibLoad

 

你可能感兴趣的:(C#/C++,Java)