1

私は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);
.
.
.
}

この通信クラスでは、データをソケットに入れる前に、RunScan オブジェクトの bytes[] を取得する必要がありますが、「//<<<<<<<」の行で BufferUnderflowException を取得します。

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();

これら2つのSigned32フィールドであるRunScanオブジェクトの8バイト(remaining()メソッドから)ByteBufferのみを返します。しかし、この行、

int cmdSize = scCmd.size();

これら 2 つの配列のサイズを含む RunScan オブジェクトの正しい長さを返します。

ハードコーディングされた長さでそれらを宣言するときにこれらの2つの配列を作成すると(コンストラクターで「新しい」ものではない)、例外なく正常に動作します。

私たちの実装の何が問題なのかを理解してくれる人はいますか?

4

3 に答える 3

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]);      
    }
}

次に、読み取りと書き込みの 2 段階のアプローチが必要になります。最初にヘッダー データの読み取り/書き込みを行い、次に本文データの読み取り/書き込みを行います。

申し訳ありませんが、現時点では詳細がわかりません。これを解決できない場合はお知らせください。コードを掘り下げます。

于 2011-08-03T14:33:07.627 に答える
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);
     }
}
于 2011-08-08T20:31:36.733 に答える
1

get()の位置を移動しByteBufferます。

scCmd.getByteBuffer().slice().get(dest)位置の移動と意図しない副作用の問題を解決する可能性があります。

scCmd.getByteBuffer().duplicate().get(dest)slice()元のバッファの間違った画像を生成する場合も、問題を解決する可能性があります。

さらに、冗長な参照を作成しているかのように見えscCmd.getByteBuffer()、同じメソッドでソース参照と子参照を呼び出しています。

scCmd.getByteBuffer()がすでに を渡している場合、これらslice()のメソッドへの冗長なアクセスは、計画したこと以外のことを確実に実行します。

于 2011-08-08T21:24:01.600 に答える