当前位置: 首页 > 知识库问答 >
问题:

java反序列化和序列化在同一个过程中

曹光霁
2023-03-14

我在序列化和反序列化同一JVM中的对象列表时遇到问题。确切地说,现在我的对象与字母表对象具有相同的引用,它有以下规则:

    VMID instanceId = new VMID();  //used in readResolve to identify persitent instances

    public Alphabet (int capacity, Class entryClass) {
        this.map = new gnu.trove.TObjectIntHashMap (capacity);
        this.entries = new ArrayList (capacity);
        this.entryClass = entryClass;
        // someone could try to deserialize us into this image (e.g., by RMI).  Handle this.
        deserializedEntries.put (instanceId, this);
    }

    public VMID getInstanceId() {
        return instanceId;
    } // for debugging

    public void setInstanceId(VMID id) { this.instanceId = id; }

    // Serialization
    private static final long serialVersionUID = 1;

    private static final int CURRENT_SERIAL_VERSION = 1;

    private void writeObject (ObjectOutputStream out) throws IOException {
        out.writeInt (CURRENT_SERIAL_VERSION);
        out.writeInt (entries.size());
        for (int i = 0; i < entries.size(); i++) {
            out.writeObject (entries.get(i));
        }
        out.writeBoolean (growthStopped);
        out.writeObject (entryClass);
        out.writeObject(instanceId);
    }

    private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException {
        int version = in.readInt ();
        int size = in.readInt();
        entries = new ArrayList (size);
        map = new gnu.trove.TObjectIntHashMap (size);
        for (int i = 0; i < size; i++) {
            Object o = in.readObject();
            map.put (o, i);
            entries. add (o);
        }
        growthStopped = in.readBoolean();
        entryClass = (Class) in.readObject();
        if (version >0 ){ // instanced id added in version 1S
            instanceId = (VMID) in.readObject();
        }
    }

    private transient static HashMap deserializedEntries = new HashMap();
    /**
     * This gets called after readObject; it lets the object decide whether
     * to return itself or return a previously read in version.
     * We use a hashMap of instanceIds to determine if we have already read
     * in this object.
     * @return
     * @throws ObjectStreamException
     */

    public Object readResolve() throws ObjectStreamException {
        Object previous = deserializedEntries.get(instanceId);
        if (previous != null){
            //System.out.println(" ***Alphabet ReadResolve:Resolving to previous instance. instance id= " + instanceId);
            return previous;
        }
        if (instanceId != null){
            deserializedEntries.put(instanceId, this);
        }
        //System.out.println(" *** Alphabet ReadResolve: new instance. instance id= " + instanceId);
        return this;
    }

现在在我的对象列表反序列化之后,在某个时候字母表引用不匹配。我用以下方法检查了一下:

for (Instance i: finalTrainingDocs){
    if (!i.getTargetAlphabet().equals(finalTraining.getTargetAlphabet())){
        System.out.println("not equals");
        System.out.println(i.getTargetAlphabet().getInstanceId() + " " + finalTraining.getTargetAlphabet().getInstanceId());
    }
    finalTraining.add(i);
    counter++;
    System.out.println("counter " + counter);
}

得到了以下结果

counter 237
counter 238
counter 239
not equals
3ce62156867eb540:6b7f0de5:141e51fcd67:-7ffa 3ce62156867eb540:6b7f0de5:141e51fcd67:-7ffa

现在看看VMId,既然它们是相同的,那么它不应该是相同的对象吗,就像上面的逻辑一样?谢谢你的帮助。

共有2个答案

端木权
2023-03-14

您正在阅读基于版本的instanceId

if (version >0 ){ // instanced id added in version 1S
    instanceId = (VMID) in.readObject();
}

所以这里也需要同样的条件

 if (CURRENT_SERIAL_VERSION >0 ){ 
      out.writeObject(instanceId);
欧阳德运
2023-03-14

一种可能是您有一个竞争条件;即两个线程同时更新反序列化条目hashmap。这可能导致您有两个Alphabet实例,其instanceId值相等。

反序列化dentries声明为volatile不足以防止这种情况。(事实上,同步不足甚至可能导致hashmap的内部数据结构被破坏。)

我不相信你正在做的是一个好主意。除了这种脆弱性(这需要更多的重量级同步来修复),你还有hashmap是内存泄漏的问题。我怀疑你会通过接受Alphabet实例被复制,并且重写等于来处理这个问题来获得更好的性能。

 类似资料:
  • 主要内容:1 Java序列化和反序列化,2 Java序列化的优点,3 java.io.Serializable接口,4 Java ObjectOutputStream,5 Java ObjectInputStream,6 Java序列化的例子,7 Java反序列化的例子1 Java序列化和反序列化 Java中的序列化是一种将对象状态写入字节流的机制。它主要用于Hibernate,RMI,JPA,EJB和JMS技术。 序列化的反向操作称为反序列化,其中字节流被转换为对象。序列化和反序列化过程与平台

  • 问题内容: 我已经开始在我的第一个android应用程序上进行工作,并且具有处理多层图像的应用程序。我能够将项目文件的平面版本导出为PNG,但我希望能够保存分层图像以供以后编辑(包括应用于某些层的任何选项,例如基于文本的层)。 无论如何,我已经确保需要写入文件的类是“可序列化的”,但是由于android.graphics.Bitmap不可序列化这一事实而遇到了一些障碍。以下代码实质上将位图作为PN

  • 我有两个Java应用程序-和。需要通过套接字发送到类的Slave实例。 Master创建这个类的实例,序列化它并通过套接字发送到Slave。 在上,一切正常。没有异常。接收数据并尝试对其进行反序列化。引发以下异常 JAVAlang.ClassNotFoundException 在类中没有错误,因为如果我用优化函数=null创建它,那么就会毫无问题地反序列化它。我试图将实例序列化到中的文件中,然后也

  • 我有一个kdtree,其节点由以下字段组成:公共静态类节点实现可序列化{ 其中DataPoint定义: 公共静态类DataPoint实现可序列化{公共可比X;公共可比Y;公共可比Z; 我想序列化树,存储在文件中并在回答范围查询时反序列化。我对这个概念od序列化的理解并不好。从我收集的任何内容中,我编写了以下函数,但不起作用。有人能帮忙吗?

  • 问题内容: 我尝试过在Java和Android之间实现跨平台序列化。我使用了Serializable,并将我的代码在Android中与台式机Java放在同一软件包中。 来源:java-desktop序列化 资料来源:Android-反序列化 学生是一类,实现了Serializable。在桌面上,我将学生实例序列化为“ thestudent.dat”。我将此文件放在Android设备上的SD卡上,并

  • 上一小节我们学习了 Java 的输入输出流,有了这些前置知识点,我们就可以学习 Java 的序列化了。本小节将介绍什么是序列化、什么是反序列化、序列化有什么作用,Serializable 接口以及 Externalizable 接口,常用序列化工具介绍等内容。 1. 序列化与反序列化 序列化在计算机科学的数据处理中,是指将数据结构或对象状态转换成可取用格式,以留待后续在相同或另一台计算机环境中,能