在字节数组中存储对象引用

时间:2012-09-16 13:14:43

标签: java arrays memory byte object-reference

我有一个字节数组和一个对象引用。

    byte[] data = new byte[128];

    Block b = new Block();

我想将参考b存储在“data”数组的最后2(或4)个字节中。

请注意:我不想序列化对象并存储在字节数组中。我需要存储一个引用新块的指针(引用)。

修改

我的Block类如下

    public class Block {
        byte[] data ;

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

基本上,数据数组将使用126个字节来存储字符串,并使用最后两个(或4个)字节来存储对另一个块的引用。它的链接列表。

我可以使用Block类的不同定义[通过在类本身中包含对Block的引用]来完成它。但是问题语句指出只应该使用2个字节的约束作为对另一个块的引用。从其他帖子我开始知道在jvm(32位)中,引用的大小为4个字节。因此我认为只能使用最后4个字节来完成

问题陈述中的代码段

  

块的最后2个字节用于指向下一个块。   假设文件是​​8块大小,那么第4个的最后2个字节   block将指向第5个块,并指向第5个块的最后2个字节   第6块等等。

5 个答案:

答案 0 :(得分:5)

  

基本上,数据数组将使用126个字节来存储字符串,并使用最后两个(或4个)字节来存储对另一个块的引用。它的链接列表。

您可以通过存储阻止索引来完成此操作。

e.g

// 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的引用]来完成它。但是问题语句指出只应该使用2个字节的约束作为对另一个块的引用。从其他帖子我开始知道在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的预算。

答案 1 :(得分:1)

您可以通过ObjectOutputStream序列化任何对象(请注意,您必须将implements Serializable添加到您的班级Block)。例如:

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

答案 2 :(得分:1)

  

我需要存储一个引用新块的指针(引用)。

基本上,你不能在纯Java中完成这项工作。

非纯Java方法(使用JNI或Unsafe类)将为您提供一个不能安全地转回Java引用的值。

原因是当GC运行时,它通常可到达的对象移动到新位置。现在,如果您在正确的引用类型字段,变量或数组槽中引用了一个对象,GC将找到该引用副本并将其更新为指向该对象的新位置。但是如果引用已经转换为字节或其他内容,那么GC将不知道字节实际上是引用的表示,并且不会更新它。因此,您的reference-represent-as-bytes现在将指向错误的位置。如果你把它变成参考并尝试使用它,可能会发生混乱。


您需要找到一种不同的方式来表示这些Block引用。如果您不愿意自己序列化Block个对象,那么显而易见的选项是某种索引或Map键。在所有情况下,您的数据结构都需要保存垃圾收集器可以访问的对象/数组中的实际引用。

答案 3 :(得分:0)

我认为你所做的是:

  1. 首先序列化Block Class。
  2. 然后使用类似下面的内容将块对象转换为字节数组。
  3. ` 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)方法从源对象复制到目标对象。

答案 4 :(得分:0)

对于java中的内存数据结构,无法做到这一点。

jvm规范故意模糊了如何存储和分配对象引用,以允许不同的jvm实现对它们如何实现垃圾收集做出不同的选择等。

你可以做的最好的事情(如果在内存中工作)是模拟一个带有大字节数组的地址空间,你在这里使用数组中的索引作为指针。

如果在磁盘上工作,这是一个不同的故事,因为基于磁盘的存储可以通过偏移和指针访问,但是你的内存数据结构变得无关紧要