瞬态和易失性变量与串行版本 uid 之间有什么关系吗?



实际上我想知道序列化的概念,以及瞬态局部变量以什么方式与serialversionuid相关,以及序列化实际上是如何发生的?

基本上没有。serialVersionUID通常用于确定哪些版本的类是相互兼容的(通常在)集群环境中,如果你想在任何上下文中支持应用程序的多个版本,你可以增加这个字段,以防止应用程序的以前版本在新字段上爆炸。

标记为transient的字段不序列化。

最后,volatile用于防止编译器在多个线程可以访问一个字段时进行不安全的优化。例如,双重检查锁定。来自维基百科

在J2SE 5.0中,这个问题已经修复了。volatile关键字现在可以确保多个线程正确处理单例实例。这个新的成语在[4]中有描述:

// Works with acquire/release semantics for volatile
// Broken under Java 1.4 and earlier semantics for volatile
class Foo {
    private volatile Helper helper;
    public Helper getHelper() {
        Helper result = helper;
        if (result == null) {
            synchronized(this) {
                result = helper;
                if (result == null) {
                    helper = result = new Helper();
                }
            }
        }
        return result;
    }
 
    // other functions and members...
}

Java中的transient关键字用于表示不应该序列化字段。摘自Java语言规范,Java SE 7版,章节8.3.1.3。瞬态字段:

变量可以被标记为transient,以表明它们不是对象持久状态的一部分。而局部变量可以序列化

令人惊讶的是,如果您在类中声明静态成员字段为transient或final成员字段为transient, java编译器不会报错。这些应该是编译时错误。因为假设对象状态的"瞬态"部分在每个实例中都在变化,所以它不能是静态的或最终的

序列化运行时与每个可序列化类关联一个版本号,称为serialVersionUID,在反序列化期间使用该版本号来验证序列化对象的发送方和接收方是否为该对象加载了与序列化兼容的类。如果接收方为对象加载了一个具有不同于相应发送方类的serialVersionUID的类,那么反序列化将导致InvalidClassException。一个可序列化的类可以通过声明一个名为"serialVersionUID"的字段来显式地声明它自己的serialVersionUID,这个字段必须是静态的、final的、long类型的:ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;如果可序列化的类没有显式声明serialVersionUID,那么序列化运行时将根据该类的各个方面计算该类的默认serialVersionUID值,如Java(TM)对象序列化规范中所述。然而,强烈建议所有可序列化的类显式声明serialVersionUID值,因为默认的serialVersionUID计算对类细节非常敏感,这些细节可能因编译器实现而有所不同,因此可能在反序列化期间导致意外的InvalidClassExceptions。因此,为了保证在不同的java编译器实现中具有一致的serialVersionUID值,可序列化的类必须声明显式的serialVersionUID值。还强烈建议显式serialVersionUID声明尽可能使用private修饰符,因为这样的声明仅适用于立即声明的类——serialVersionUID字段作为继承成员是无效的。

Java文档说:

"默认的serialVersionUID计算对类细节高度敏感,这些细节可能因编译器的实现而异,因此可能在反序列化期间导致意外的InvalidClassExceptions "。

你必须声明serialVersionUID,因为它给我们更多的控制。

最新更新