我对Javolution有以下实现:
public class RunScan extends Struct
{
public final Signed32 numOfClusters = new Signed32();
public final ClusterData[] clusters;
public final Signed32 numOfRecons = new Signed32();
public final ReconData[] recons ;
public RunScan (int numOfClusters, int numOfRecons)
{
this.numOfClusters.set(numOfClusters);
this.numOfRecons.set(numOfRecons);
clusters = array(new ClusterData[numOfClusters]);
recons = array(new ReconData[numOfRecons]);
}
}
public class ClusterData extends Struct
{
public final UTF8String scanType = new UTF8String(CommInterfaceFieldConstants.SCAN_TYPE_SIZE);
public final UTF8String patientId = new UTF8String(CommInterfaceFieldConstants.PATIENT_ID_SIZE);
.
.
.
}
public class ReconData extends Struct
{
public final UTF8String patientId = new UTF8String(CommInterfaceFieldConstants.PATIENT_ID_SIZE);
public final UTF8String scanSeriesId = new UTF8String(CommInterfaceFieldConstants.SCAN_SERIES_ID_SIZE);
.
.
.
}
在我们的通信类中,在将数据放入socket之前,我们需要获取RunScan对象的bytes [],但是我们在“//<<<<<<<<<<<<<< <“:
private byte[] getCmdBytes(Struct scCmd)
{
ByteBuffer cmdBuffer = scCmd.getByteBuffer();
int cmdSize = scCmd.size();
byte[] cmdBytes = new byte[cmdSize];
if (cmdBuffer.hasArray())
{
int offset = cmdBuffer.arrayOffset() + scCmd.getByteBufferPosition();
System.arraycopy(cmdBuffer.array(), offset, cmdBytes, 0, cmdSize);
}
else
{
String msg = "\n\ncmdBufferRemaining=" + cmdBuffer.remaining() + ", cmdBytesSize=" + cmdBytes.length + "\n\n";
System.out.println(msg);
cmdBuffer.position(scCmd.getByteBufferPosition());
cmdBuffer.get(cmdBytes); //<<<<<<<<<< underFlowException
}
return cmdBytes;
}
此方法适用于其他情况。发生异常是因为这一行,
ByteBuffer cmdBuffer = scCmd.getByteBuffer();
只返回RunScan对象的8个字节(来自剩余的()方法)ByteBuffer,这是两个Signed32字段,我想。但是这一行,
int cmdSize = scCmd.size();
返回RunScan对象的正确长度,其中包括这两个数组的大小。
如果我在使用硬编码长度声明它们(在构造函数中不是“new”)时创建这两个数组,它可以正常工作而没有任何异常。
任何人都可以帮我弄清楚我们的实施有什么问题?
答案 0 :(得分:2)
我的代码遇到了类似的情况。通常,对于当前的Struct对象,您不能在与包含数组中元素数的成员相同的结构中定义可变长度数组。
尝试这样的事情:
public class RunScanHeader extends Struct
{
public final Signed32 numOfClusters = new Signed32();
public final Signed32 numOfRecons = new Signed32();
}
public class RunScanBody extends Struct
{
public final ClusterData[] clusters;
public final ReconData[] recons ;
public RunScan (int numOfClusters, int numOfRecons)
{
clusters = array(new ClusterData[numOfClusters]);
recons = array(new ReconData[numOfRecons]);
}
}
然后,你需要一个两阶段的读写方法,首先读/写头数据,然后读/写身体数据。
抱歉,我目前没有更多详细信息,如果你无法解决这个问题,请告诉我,我会深入查看我的代码。
答案 1 :(得分:1)
初始化顺序很重要,它定义了每个字段的位置。在声明字段时完成初始化(最常见的情况)。或者,如果在构造函数中执行此操作,则必须记住在成员初始化之后调用构造函数。以下是在构造函数中完成初始化的示例:
public class RunScan extends Struct {
public final Signed32 numOfClusters;
public final ClusterData[] clusters;
public final Signed32 numOfRecons;
public final ReconData[] recons ;
public RunScan (int numOfClusters, int numOfRecons) {
// Initialization done in the constructor for all members
// Order is important, it should match the declarative order to ensure proper positioning.
this.numOfClusters = new Signed32();
this.clusters = array(new ClusterData[numOfClusters]);
this.numOfRecons = new Signed32();
this.recons = array(new ReconData[numOfRecons]);
// Only after all the members have been initialized the set method can be used.
this.numOfClusters.set(numOfClusters);
this.numOfRecons.set(numOfRecons);
}
}
答案 2 :(得分:1)
get()
会移动ByteBuffer
的位置。
scCmd.getByteBuffer().slice().get(dest)
可能会解决您移动位置和意外副作用的问题。
scCmd.getByteBuffer().duplicate().get(dest)
生成错误的原始缓冲区图片, slice()
也可能会解决您的问题。
此外,似乎scCmd.getByteBuffer()
创建了一个冗余引用,并且您使用相同的方法调用源和子引用。
如果scCmd.getByteBuffer()
已经通过了slice()
,那么您对这些方法的冗余访问肯定会做出除您计划之外的其他操作。