原始类型的瞬态最终和瞬态最终包装类型之间的差异

时间:2014-08-14 09:19:35

标签: java

transient final inttransient final Integer之间有何不同。

使用int

transient final int a = 10;

序列化之前:

a = 10

序列化后:

a = 10

使用Integer

transient final Integer a = 10;

序列化之前:

a = 10

序列化后:

a = null

完整代码:

public class App implements Serializable {
    transient final Integer transientFinal = 10;

    public static void main(String[] args) {
    try {
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(
                "logInfo.out"));
        App a = new App();
        System.out.println("Before Serialization ...");
        System.out.println("transientFinalString = " + a.transientFinal);
        o.writeObject(a);
        o.close();
    } catch (Exception e) {
        // deal with exception
        e.printStackTrace();
    }

    try {

        ObjectInputStream in = new ObjectInputStream(new FileInputStream(
                "logInfo.out"));
        App x = (App) in.readObject();
        System.out.println("After Serialization ...");
        System.out.println("transientFinalString = " + x.transientFinal);
    } catch (Exception e) {
        // deal with exception
                    e.printStackTrace();
    }
}

}

2 个答案:

答案 0 :(得分:6)

如文章

所述

http://www.xyzws.com/Javafaq/can-transient-variables-be-declared-as-final-or-static/0

使字段瞬态将阻止其序列化,但有一个例外:

  

此规则只有一个例外,即瞬态最终字段成员初始化为constant expressionprimitive type中定义的成员。因此,即使在反序列化对象之后,以这种方式声明的字段成员也将保持其常量值表达式。

如果您将访问提到的JSL,您将知道

  

常量表达式是表示值StringInteger

的表达式

class SomeClass implements Serializable { public transient final int a = 10; public transient final Integer b = 10; public transient final String c = "foo"; public static void main(String[] args) throws Exception { SomeClass sc = new SomeClass(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(sc); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream( bos.toByteArray())); SomeClass sc2 = (SomeClass) ois.readObject(); System.out.println(sc2.a); System.out.println(sc2.b); System.out.println(sc2.c); } } 不是原始类型,它不是String,因此它不被视为常量表达式的候选者,因此它的值在序列化后不会保留。

演示:

10
null
foo

输出:

{{1}}

答案 1 :(得分:2)

反序列化后,只有常量表达式将分配给字段。并且Integer不能表示为常量表达式,只有原始类型和字符串可以符合http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28

http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.3中指定了final int 保持其值的原因:

Even then, there are a number of complications. If a final field is initialized 
to a compile-time constant expression (§15.28) in the field declaration, changes 
to the final field may not be observed, since uses of that final field are 
replaced at compile time with the value of the constant expression.

因此,该字段的用法在编译时会被常量替换,并且不会受到运行时序列化的影响。