2

バイト配列とオブジェクト参照があります。

    byte[] data = new byte[128];

    Block b = new Block();

「データ」配列の最後の 2 (または 4) バイトに参照 b を格納したい。

親切に注意してください:オブジェクトをシリアル化し、バイト配列に格納したくありません。新しいブロックを参照するポインター (参照) を格納する必要があります。

編集

私のブロッククラスは次のとおりです

    public class Block {
        byte[] data ;

        public Block(){
            data = new byte[128];
        }
}

基本的に、データ配列は 126 バイトを使用して文字列を格納し、最後の 2 (または 4) バイトを使用して別のブロックへの参照を格納します。その一種のリンク リスト。

[クラス自体に Block への参照を含めることにより] Block クラスの別の定義を使用してそれを行うこともできました。他の投稿から、jvm(32 ビット) では参照のサイズが 4 バイトであることを知りました。したがって、最後の4バイトを使用してのみ実行できると思います

問題文の抜粋

ブロックの最後の 2 バイトは、次のブロックを指すために使用されます。ファイルのサイズが 8 ブロックの場合、4 番目のブロックの最後の 2 バイトは 5 番目のブロックを指し、5 番目のブロックの最後の 2 バイトは 6 番目のブロックを指す、というようになります。

4

5 に答える 5

5

基本的に、データ配列は 126 バイトを使用して文字列を格納し、最後の 2 (または 4) バイトを使用して別のブロックへの参照を格納します。その一種のリンク リスト。

これは、ブロック インデックスを格納することで実行できます。

例えば

// list of blocks so you can lookup any block using a 16-bit index.
List<Block> blocks = new ArrayList<Block>();

int indexInBlocksToNext = ...
data[126] = (byte) (indexInBlocksToNext >> 8);
data[127] = (byte) indexInBlocksToNext;

[クラス自体に Block への参照を含めることにより] Block クラスの別の定義を使用してそれを行うこともできました。他の投稿から、jvm(32 ビット) では参照のサイズが 4 バイトであることを知りました。したがって、最後の4バイトを使用してのみ実行できると思います

すべての 32 ビット システムは、32 ビット ポインターまたは参照を使用します。数値を介してオブジェクトを参照するグローバルな方法がないため、Java で参照を配置することはできません。オブジェクトがメモリ内のどこにあったかを取得できますが、この場所はいつでも変更できます。


Java 7 では、開始する前に使用される最小メモリは約 1.3 MB です。

$ java -mx1200k -version
Error occurred during initialization of VM
Too small initial heap for new size specified
$ java -mx1300k -version
java version "1.7.0_05"
Java(TM) SE Runtime Environment (build 1.7.0_05-b05)
Java HotSpot(TM) 64-Bit Server VM (build 23.1-b03, mixed mode)

これは、プログラムが開始される前に、予算の 1 MB を超えて使用したことを意味します。

于 2012-09-16T13:36:47.810 に答える
1

を介して任意のオブジェクトをシリアル化できます(クラスObjectOutputStreamに追加する必要があることに注意してください)。例えば:implements SerializableBlock

Block block = new Block();
// ...
ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(new File("test.dat"))));
oos.wrtieObject(block);
oos.close();

そしてそれを次のように読んでください:

ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(new File("test.dat"))));
Block block = (Block) ois.readObject();
ois.close();
于 2012-09-16T13:17:16.570 に答える
1

新しいブロックを参照するポインター (参照) を格納する必要があります。

基本的に、純粋な Java ではこれを行うことはできません。

これを (JNI またはUnsafeクラスを使用して) 純粋な Java 以外の方法で行うと、安全に Java 参照に戻すことができない値が得られます。

その理由は、GC が実行されると、通常、到達可能なオブジェクトが新しい場所に移動されるためです。適切な参照型のフィールド、変数、または配列スロットにオブジェクトへの参照がある場合、GC はその参照コピーを見つけて、オブジェクトの新しい場所を指すように更新します。しかし、参照がバイトなどに変換されている場合、GC はバイトが実際に参照の表現であることを認識せず、更新しません。そのため、バイトとして表現された参照は間違った場所を指すようになります。それを参照に戻して使用しようとすると、混乱が生じる可能性があります。


これらの参照を示す別の方法を見つける必要がありますBlock。オブジェクト自体をシリアル化する気がない場合Block、明らかなオプションは、インデックスまたはある種の Map キーです。いずれの場合も、データ構造は、ガベージ コレクターが到達可能なオブジェクト/配列内の実際の参照を保持する必要があります。

于 2012-09-16T14:01:27.793 に答える
0

これは、Java のメモリ内データ構造では実行できません。

jvm の仕様は、ガベージ コレクションの実装方法などに関して、さまざまな jvm 実装がさまざまな選択を行えるようにするために、オブジェクト参照がどのように格納および割り当てられるかについて意図的にあいまいです。

(メモリ内で作業している場合)できる最善の方法は、配列内のインデックスをポインターとして使用している大きなバイト配列でアドレス空間をエミュレートすることです。

ディスク上で作業している場合、ディスク ベースのストレージはオフセットによってアクセス可能であり、ポインターは理にかなっていますが、メモリ内のデータ構造は無関係になるため、これは別の話です。

于 2012-09-16T14:03:52.060 に答える
0

あなたができることは次のとおりだと思います:

  1. 最初のシリアライズ ブロック クラス。
  2. 次に、次のようなものを使用して、ブロック オブジェクトをバイト配列に変換します。

` public byte[] toByteArray(Object obj) {//

    byte[] bytes = null;
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    try {
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        oos.flush();
        oos.close();
        bos.close();
        bytes = bos.toByteArray();
    } catch (IOException ex) {
        System.out.println(ex);
    }
    return bytes;

`

  1. System.arraycopy (src, srcPos, dest, destPos, length) メソッドを使用して、ソース オブジェクトから宛先オブジェクトにコピーします。
于 2012-09-16T13:36:03.077 に答える