Java 反序列化时如何正确使用瞬态关键字?

Java 反序列化时如何正确使用瞬态关键字?,java,design-patterns,serializable,transient,Java,Design Patterns,Serializable,Transient,我有以下课程 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 tr

我有以下课程

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.
        }
    }
}
这种方式很烦人,因为反序列化方法需要记住设置对象。这对其他在项目中工作的人来说是非常不直观的

2)
设置方法自动检查和修复自身

public void set(int newVal) {
    if (num != newVal) {
        if (listeners == null) listeners = new HashSet<>();
        ...
    }
}

但这种方式似乎也不必要地复杂。肯定有更好的解决办法吗?如何正确使用瞬态?方法2是一个很好的方法。在我的实践中,当对集合使用for循环或stream/foreach时,我将始终检查null

可以通过初始化set-in-addListener方法来完成优化,以便在集合为空时直接返回set方法

对于您的性能,null check语句不会影响性能,因为For循环和notify方法将花费更多时间,并且可以忽略它。

来源:

然而,有一个奇怪而狡猾的解决办法。通过使用内置的 序列化机制的特性,开发人员可以增强 通过在类文件中提供两个方法来执行正常过程

这些方法是:

  • private void writeObject(ObjectOutputStream out)抛出IOException
  • private void readObject(ObjectInputStream in)引发IOException,
    ClassNotFoundException
  • 因此,您只需要实现如下所示的
    readObject
    ,在默认反序列化之后,只需创建
    HashSet
    的新实例。例如:

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        this.listeners = new HashSet<>();
    }
    
    private void readObject(ObjectInputStream in)抛出IOException、ClassNotFoundException{
    in.defaultReadObject();
    this.listeners=new HashSet();
    }
    
    对于方法2,这种方式也是不好的,因为检查这是一个非常快速的过程op@ScaryWombat是的,但是如果您考虑这些对象的生命周期,
    set
    函数可能会在许多对象中被调用数十万次。可能有一种更好的方法来解决这个问题。他们对过早优化怎么说?在我的代码中,我确信我有更大的问题要考虑。@ScaryWombat我理解你的立场,但我认为这不是过早的优化,而是CPU周期简洁的编码实践。无需争论;-)也许其他人会插话。我明白你现在在说什么。您的意思是,只需将集合
    null
    保留,直到调用方真正想要添加一些内容。只有这样,您才能初始化它并添加。我相信在这种情况下我会这么做。但是如果我说。。。对对象功能非常重要的三个变量?拯救他们都是浪费。但是,使
    暂时
    将导致对象的一半为
    null
    。这正是我想要的。非常感谢。
    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());
        }
    }
    
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        this.listeners = new HashSet<>();
    }