【发布时间】:2020-02-25 06:39:10
【问题描述】:
我有以下课程
public class Num implements Serializable, Observable {
private int num; // number which should be serialized
// listeners who are watching for changes in this Num
// No need to serialize these -- pointless to do so.
private transient Set<Observer> listeners = new HashSet<>();
@Override public void addListener(Observer o) { listeners.add(o); }
@Override public void removeListener(Observer o) { listeners.remove(o); }
public void set(int newVal) {
if (num != newVal) {
num = newVal; // set the value.
for (Observer o : listeners)
o.notify(); // Notify listeners that the value changed.
}
}
}
当我序列化这个类时,它运行良好并且num 被保存。当我对类进行反序列化时,num 已加载,但 listeners 未加载并设置为 null。然后我的程序在for (Observer o : listeners) 行崩溃。
我想出了一些解决方案,但它们都是糟糕的解决方案。
1) 有一个“重建”transient 字段的设置方法。
public void setup() {
if (listeners != null) throw new Exception("Already setup!");
listeners = new HashSet<>();
}
这种方式很烦人,因为反序列化方法需要记住设置对象。对于从事该项目的其他人来说,这非常不直观。
2)让set方法自动检查和修复自己
public void set(int newVal) {
if (num != newVal) {
if (listeners == null) listeners = new HashSet<>();
...
}
}
这种方式也很糟糕,因为检查会一遍又一遍地进行,即使只需要执行一次。
3) 从class Num 中删除Observable,去掉listeners 等。然后创建一个包含Num 实例的不可序列化类。
public class Num implements Serializable {
public int num;
}
public class ObservableNum impements Observable {
private Num n;
public ObservableNum() { n = new Num(); } // constructor
private ObservableNum(Num n) { this.n = n; } // constructor
...
public static ObservableNum loadNum(...) {
ObjectInputStream ois = ...;
return new ObservableNum((Num) ois.readObject());
}
}
但这种方式似乎也不必要地复杂。当然必须有更好的解决方案?瞬态如何正确使用?
【问题讨论】:
-
对于方法2,这种方法也不好,因为检查...... - 这是一个非常快速的操作
-
@ScaryWombat 是的,但是如果您考虑这些对象的生命周期,
set函数可能会在许多对象中被调用数十万次。可能有比这更好的方法来解决这个问题。 -
他们对过早优化有什么看法?在我的代码中,我确信我有更大的问题需要考虑。
-
@ScaryWombat 我理解你的立场,但我认为这与其说是过早的优化,不如说是关于 CPU 周期意识的编码实践。
-
无需争论 ;-) 也许其他人会插话。
标签: java design-patterns serializable transient