1

我只是在学习 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 是对同一个对象的引用。

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

这在Java中一定是一个很常见的问题,其他人是怎么解决的呢?

4

4 回答 4

1

正如您所指出的,要么是深拷贝,要么可能是序列化。您可以存储一个序列化的字符串,然后稍后再从中重建对象。

于 2013-02-24T13:05:15.917 回答
0

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

在该模式中,您有一个有状态的对象Originator,它负责保存和恢复其状态的快照。状态本身保存在一个名为 的包装类中Memento,这些类存储在CareTaker.

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

一些对象持久性库提供事务和快照的实现。看看Prevayler,它是 Java 的对象持久性库和流行系统模式的实现。该库以事务的形式捕获对对象的更改并将它们存储在内存中。如果您需要持久存储 POJO,您可以定期将对象的快照保存在磁盘上,并在需要时恢复它们。

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

于 2013-02-24T14:31:03.567 回答
0

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

如果你只使用myLargeObject fromExample,你可以使用

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

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

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

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

此外,非常重要的是,如果你有一个底层数据结构,你应该为它遍历整个结构。否则,您可能会遇到对象引用问题。

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

于 2013-02-24T13:26:54.277 回答
0

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

MyObject myLargeMyObjectRecovery = myLargeObject;

在您的代码中也是如此。myLargeMyObjectRecoverymyLargeObject引用内存中的相同对象。

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

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

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();
于 2013-02-24T13:51:20.833 回答