我的目标是创建一个数据结构,它应该在内存中具有以下表示:
int countOfElements; // 4 bytes
int time_1; // 4 bytes
double price_1; // 8 bytes
int time_2; // 4 bytes
double price_2; // 8 bytes
int time_3; // 4 bytes
double price_3; // 8 bytes
. . . . .
int time_n; // 4 bytes, n = countOfElements
double price_n; // 8 bytes, n = countOfElements
不幸的是,我无法在内存中选择此结构的表示(字段顺序和类型),因为它与操作系统上的另一个进程相关。数据结构旨在通过使用WinAPI函数放置在共享内存上,此数据结构的目的是数据交换。因此,我还需要在java中获取指向此数据结构的指针... 因此,我努力实现这种数据结构如下:
import java.util.List;
import java.util.Arrays;
import com.sun.jna.Structure;
public class TQuote extends Structure {
public int time;
public double price;
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"time", "price"});
}
}
public class TSharedArray extends Structure {
public int countOfElements;
public TQuote[] elements;
public TSharedArray(int size) {
super();
countOfElements = size;
elements = new TQuote[size];
for (int i = 0; i < size; i++) elements[i] = new TQuote();
}
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"countOfElements", "elements"});
}
}
尽管如此,我尝试实例化结构TSharedArray structure = new TSharedArray(10);
会引发异常:
/*
Invalid Structure field in class xxx$TSharedArray, field name 'elements' (class xxx$TQuote): Can't instantiate class xxx$TQuote (java.lang.InstantiationException: xxx$TQuote)
java.lang.IllegalArgumentException: Invalid Structure field in class xxx$TSharedArray, field name 'elements' (class xxx$TQuote): Can't instantiate class xxx$TQuote (java.lang.InstantiationException: xxx$TQuote)
at com.sun.jna.Structure.validateField(Structure.java:962)
at com.sun.jna.Structure.validateField(Structure.java:954)
at com.sun.jna.Structure.validateFields(Structure.java:972)
at com.sun.jna.Structure.<init>(Structure.java:186)
at com.sun.jna.Structure.<init>(Structure.java:180)
at com.sun.jna.Structure.<init>(Structure.java:167)
at com.sun.jna.Structure.<init>(Structure.java:159)
at xxx$TSharedArray.<init>(xxx.java:35)
at xxx.onStart(xxx.java:57)
at java.lang.Thread.run(Unknown Source)
*/
xxx.java第35行中的Java代码是super();
任何想法,如何修复它?
此外,我注意到一件奇怪的事情......让我们假设,我们有三个结构,每个结构都包含两个字段:
public class TIntInt extends Structure {
public int int1;
public int int2;
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"int1", "int2"});
}
}
public class TDblDbl extends Structure {
public double dbl1;
public double dbl2;
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"dbl1", "dbl2"});
}
}
public class TIntDbl extends Structure {
public int int1;
public double dbl1;
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"int1", "dbl1"});
}
}
第一个(TIntInt)的大小与预期的2 * 4 = 8个字节相同,第二个(TDblDbl)的大小与预期的2 * 8 = 16个字节相同,但第三个(TIntDbl - it&#39; s与TQuote相同)的大小为16字节而不是预期的4 + 8 = 12。为什么:
System.out.println("TIntInt.size()=" + new TIntInt().size()); // 8 bytes, Ok
System.out.println("TDblDbl.size()=" + new TDblDbl().size()); // 16 bytes, Ok
System.out.println("TIntDbl.size()=" + new TIntDbl().size()); // 16 bytes!!! Why?
答案 0 :(得分:0)
使用的内存量以8字节块增加。有关详细信息,请参阅https://stackoverflow.com/a/321436/3915166
答案 1 :(得分:0)
必须初始化Structure
中的任何数组字段。请注意,不支持数组大小为零。
public class TSharedArray extends Structure {
public int countOfElements;
public TQuote[] elements = new TQuote[1];
public TSharedArray() {
this(1);
}
public TSharedArray(Pointer p) {
super(p);
countOfElements = (int)readField("countOfElements");
elements = new TQuote[countOfElements];
read();
}
public TSharedArray(int size) {
countOfElements = size;
elements = (TQuote[])new TQuote().toArray(size);
}
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"countOfElements", "elements"});
}
}
至于你的第二个问题,大小的差异是由于结构填充。通常字段将在与其大小相等的内存边界上对齐,因此在int
字段后将有4个字节填充,以便在8字节边界上对齐double
字段。
修改强>
用作字段的任何结构必须具有public,no-args构造函数(并且拥有基于指针的构造函数也是一个好主意)。您看到的错误是因为JNA无法通过反射创建TQuote
的实例。您需要解决该问题或明确为该字段创建预填充数组:
public TQuote[] elements = (TQuote[])new TQuote().toArray(1);
<强>对齐强>
如果您想避免默认的平台对齐,可以使用Structure.ALIGN_NONE
(请参阅Structure.setAlignType()
)。
答案 2 :(得分:0)
经过多次尝试和实验后,我发现在没有Exception的情况下运行的唯一代码是使用Structure.ByReference
:
public class TQuote extends Structure {
public class ByReference extends TQuote implements Structure.ByReference {}
public int time;
public double price;
@Override
protected List getFieldOrder() {
return Arrays.asList("time", "price");
}
}
public class TSharedArray extends Structure {
public int countOfElements;
public TQuote.ByReference[] elements;
public TSharedArray(int size) {
super();
countOfElements = size;
elements = new TQuote.ByReference[size];
}
@Override
protected List getFieldOrder() {
return Arrays.asList("countOfElements", "elements");
}
}
尽管如此,上面的代码并没有达到我的目标,因为它形成了一个引用数组,而不是一个值数组。因此,结构的内存表示不合适。
我通过尝试解决结构问题而放弃......现在我有另一个不使用结构的解决方案:我在Pointers的帮助下创建了所需的内存分配。