简体   繁体   English

使用单例设计模式进行序列化

[英]Serialization with singleton design pattern

I have a problem with serialization of a class using the singleton pattern. 我在使用单例模式对类进行序列化时遇到问题。 First let me introduce the code: 首先让我介绍一下代码:

import java.io.ObjectStreamException;
import java.io.Serializable;

import org.ejml.simple.SimpleMatrix;

public class Operation implements Serializable {

    private static final long serialVersionUID = 1L;

    private final static int CONSTANT = 10;

    private SimpleMatrix data;
    private Long timestamp;

    private static Operation instance = new Operation ();

    private Operation () {
        data = new SimpleMatrix(1, CONSTANT);
    }

    protected static Operation getInstance() {
        return instance;
    }

    //Hook for not breaking the singleton pattern while deserializing.
    private Object readResolve() throws ObjectStreamException {
          return instance;
    }


    protected void setData(SimpleMatrix matrix) {
        this.data = matrix;
    }

    protected SimpleMatrix getData() {
        return data;
    }

    public Long getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Long timestamp) {
        this.timestamp = timestamp;
    }
}

I have three problems with it hoping that somebody can help me: 我有三个问题,希望有人能帮助我:

  1. As far as I know, static fields are no serialized. 据我所知,静态字段没有序列化。 So if I deserialize is my final static field CONSTANT set to 10? 因此,如果我反序列化,我的最终静态字段CONSTANT是否设置为10? If not, how can I make this? 如果没有,我该怎么做? This is very important. 这个非常重要。

  2. As you can see, in the constructor a new matrix is created. 如您所见,在构造函数中创建了一个新矩阵。 If I deserialize, is my data overwritten by this constructor? 如果我反序列化,此构造函数会覆盖我的data吗? For deserialization I want the data of the serialized version and not a new matrix. 对于反序列化,我需要序列化版本的data ,而不是新的矩阵。 The constructor I only need the first time before serialization to instantiate the object. 构造函数我只需要在序列化之前第一次实例化该对象。

  3. Before I serialize I will set the field timestamp to the time of serialization. 在序列化之前,我将字段timestamp设置为序列化的时间。 After deserialization I would like to compare this field with the timestamp of some files (to see if files have changed since serialization). 反序列化后,我想将此字段与某些文件的时间戳进行比较(以查看自序列化以来文件是否已更改)。 What sort of timestamp should I use for both the serialization time and the last modified time of files so that I can easily compare? 我应该为文件的序列化时间和上次修改时间使用哪种时间戳,以便可以轻松比较?

  1. The static constant is associated with the class, so serialization and deserialization of your instance won't impact it at all. 静态常量与该类相关联,因此实例的序列化和反序列化完全不会对其产生影响。

  2. For the deserialization to work, you need to set the singleton's data to the deserialized instance data: 为了使反序列化起作用,您需要将单例的数据设置为反序列化的实例数据:

     private Object readResolve() throws ObjectStreamException { instance.setData(getData()); return instance; } 
  3. The timestamp can stay as a Long, that's fine. 时间戳记可以保持为Long,这很好。 Use System.currentTimeMillis(), you'll be able to compare with a File object lastModified() date. 使用System.currentTimeMillis(),您将能够与File对象的lastModified()日期进行比较。 Just set the field when you serialize: 只需在序列化时设置字段即可:

     private void writeObject(java.io.ObjectOutputStream out) throws IOException{ timestamp=System.currentTimeMillis(); out.defaultWriteObject(); } 

A test I've made to be sure of what I say, using a String instead of a matrix as in your code: 为了确保我所说的,我做了一个测试,使用字符串而不是代码中的矩阵:

public static void main(String[] args) throws Exception {
    Operation op=getInstance();
    op.setData("test1");
    byte[] ds=serialize();
    System.out.println(new Date(getInstance().timestamp));
    op.setData("test2");
    deserialize(ds);
    System.out.println(getInstance().getData());

}

This gives me the current date and test1 , since the deserialize instance has overriden the current instance. 这给了我当前日期和test1 ,因为反序列化实例已覆盖当前实例。 serialize and deserialize simply convert between the instance and bytes. serializedeserialize serialize只需在实例和字节之间进行转换即可。

I would suggest that you adopt the Enum Singleton approach for implementing Singletons, as handling Serialization would be done for free. 我建议您采用Enum Singleton方法来实现Singleton,因为处理Serialization是免费的。 In your case it would be 在你的情况下

public enum Operation {
    INSTANCE; 
    // No need to handle Serialization 
}

Quoting Joshua Bloch in Effective Java " a single-element enum type is the best way to implement a singleton. " 有效Java引用Joshua Bloch:单元素枚举类型是实现单例的最佳方法。

There are plenty benefits to this approach, you can find out here 这种方法有很多好处,您可以在这里找到
And also For instance control, prefer enum types to readResolve 而且对于实例控件,更喜欢枚举类型来读取

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM