在Java中恢复到旧对象状态

时间:2013-02-24 13:03:45

标签: java oop

我只是在学习Java,但我一遍又一遍地遇到同样的问题

如何有效地恢复某个对象的旧状态?

public class Example {
    MyObject myLargeObject;

    public void someMethod(){
        MyObject myLargeMyObjectRecovery = myLargeObject;

        /**
         * Update and change myLargeObject
         */

        if(someCondition){
            //revert to previous state of myLargeObject
            myLargeObject = myLargeMyObjectRecovery;
        }
    }
}

以上是我希望代码工作的方式,但显然不会,因为myLargeObject和myLargeObjectRecovery是对同一个对象的引用。

一种解决方案是创建一个复制构造函数。这对于小对象来说很好,但是如果我有一个大对象(在我的项目中,对象是一个大的2D数组意味着我将不得不遍历所有条目),这种方式感觉不对。

这一定是Java中一个非常普遍的问题,其他人如何绕过它呢?

4 个答案:

答案 0 :(得分:1)

如您所述,深层复制或可能是序列化。您可以存储序列化字符串,然后稍后从中重新构建对象。

答案 1 :(得分:0)

最佳解决方案取决于您是否对MyObject实例进行了外部引用。

如果您仅使用myLargeObject课程中的Example ,则可以使用

  • 在保存点上序列化您的对象,并在还原点进行反序列化(序列化的byte[]必须为transient
  • 使用复制构造函数(进行深度复制)在保存点创建一个新实例,并在还原点替换该引用。

如果您可以访问来自外部的MyObject实例 ,那么它会变得更有趣,您必须引入同步。

  • MyObject上的所有方法必须为synchronized(以避免不一致的阅读)
  • 您应该使用synchronized void saveState()方法保存您的状态(通过序列化复制构造函数)(后者更好)
  • 您应该有一个synchronized void restoreState(),在内部恢复您的状态(对于复制字段,您可以使用带有复制构造函数的公共代码片段)

在所有情况下,建议关闭事务(某种commit()),这意味着当你到达那里时,你可以删除已保存的状态。

此外,非常重要的是,如果您有基础数据结构,那么应该遍历整个结构。否则,您可能会遇到对象引用问题。

小心使用 JPA实体或任何外部管理的对象,这些方法中的任何一种都不太可能与它们一起使用。

答案 2 :(得分:0)

如果将对象分配给另一个对象,则jvm引用内存中的同一对象。因此,对象的更改将在引用的其他对象中。

MyObject myLargeMyObjectRecovery = myLargeObject;

代码中的内容相同。 myLargeMyObjectRecoverymyLargeObject在内存中引用相同的对象。

如果要精确复制任何对象,可以使用Object.clone()方法。此方法将复制对象并返回一个对象,该对象引用其字段及其valus与coppied对象相同的另一个对象。

由于克隆方法受到保护,因此无法直接访问它。您可以根据您的要求实现Prototype模式。

http://www.avajava.com/tutorials/lessons/prototype-pattern.html

public class MyObject{

//fields, getters, setters and other methods.

public MyObject doClone()
    {
        MyObject clonedObject = this.clone(); //you may need to override clone()depending on your requirements.
return clonedObject;
    }

    }

并在您的代码中调用它

MyObject myLargeMyObjectRecovery = myLargeObject.doClone();

答案 3 :(得分:0)

Memento Pattern解决了恢复到以前状态问题的设计问题。当您需要捕获对象的一个​​或多个状态并能够恢复它们时,此方法很有用。将其视为N步撤消操作,就像在文本编辑器中一样。

在模式中,您有一个有状态对象Originator,它负责保存和恢复其状态的快照。状态本身保存在名为Memento的包装类中,它存储在CareTaker中并通过{{1}}访问。

在这种方法中,最简单的想法是深层复制对象。但是,这在性能和空间方面可能效率低下,因为您只存储整个对象而不是变更集。

某些对象持久性库提供事务和快照的实现。看一下Prevayler,它是java的对象持久性库和prevalent system pattern的实现。库以事务的形式捕获对象的更改并将它们存储在内存中。如果需要持久存储POJO,可以定期将对象的快照保存在磁盘上,并在需要时还原为它们。

您可以在此SO问题中找到有关序列化POJO的更多信息:Is there a object-change-tracking/versioning Java API out there?