为什么Joda Time序列化形式这么大,怎么办呢?

时间:2013-09-09 14:16:18

标签: java serialization jodatime

在我的机器上,以下代码段:

DateTime now = DateTime.now();
System.out.println(now);
System.out.println("Date size:\t\t"+serialiseToArray(now).length);
System.out.println("DateString size:\t"+serialiseToArray(now.toString()).length);
System.out.println("java.util.Date size:\t"+serialiseToArray(new Date()).length);
Duration twoHours = Duration.standardHours(2);
System.out.println(twoHours);
System.out.println("Duration size:\t\t"+serialiseToArray(twoHours).length);
System.out.println("DurationString size:\t"+serialiseToArray(twoHours.toString()).length);

提供以下输出:

2013-09-09T15:07:44.642+01:00
Date size:      273
DateString size:    36
java.util.Date size:    46
PT7200S
Duration size:      107
DurationString size:    14

正如您所看到的,org.joda.time.DateTime对象比它的String形式大5倍以上,它似乎完美地描述了它,并且java.util.Date等价。表示2小时的Duration对象也比我预期的要大得多,因为查看源它似乎唯一的成员变量是单个long值。

为什么这些序列化对象如此之大?是否有任何预先存在的解决方案来获得较小的代表?

serialiseToArray方法,供参考:

private static byte[] serialiseToArray(Serializable s)
{
    try
    {
        ByteArrayOutputStream byteArrayBuffer = new ByteArrayOutputStream();
        new ObjectOutputStream(byteArrayBuffer).writeObject(s);
        return byteArrayBuffer.toByteArray();
    }
    catch (IOException ex)
    {
        throw new RuntimeException(ex);
    }
}

2 个答案:

答案 0 :(得分:7)

序列化有一些开销。在这种情况下,您最常注意到的开销是在实际输出中描述了类结构。由于Duration具有基类(BaseDuration)和两个接口(ReadableDurationSerializable),因此该开销略大于Date的开销(它没有基类,只有一个接口。)

使用序列化文件中的完全限定类名引用这些类,因此创建了相当多的字节。

好消息:每个输出流只支付一次开销。如果序列化另一个Duration对象,则大小差异应该相当小。

我已使用the jdeserialize project查看序列化java.util.DateDuration的结果(请注意,此工具无需访问.class个文件,因此它转储的所有信息实际上都包含在序列化数据中:

java.util.Date的结果:

read: java.util.Date _h0x7e0001 = r_0x7e0000;
//// BEGIN stream content output
java.util.Date _h0x7e0001 = r_0x7e0000;
//// END stream content output

//// BEGIN class declarations (excluding array classes)
class java.util.Date implements java.io.Serializable {
}

//// END class declarations

//// BEGIN instance dump
[instance 0x7e0001: 0x7e0000/java.util.Date
  object annotations:
    java.util.Date
        [blockdata 0x00: 8 bytes]

  field data:
    0x7e0000/java.util.Date:
]
//// END instance dump

Duration的结果:

read: org.joda.time.Duration _h0x7e0002 = r_0x7e0000;
//// BEGIN stream content output
org.joda.time.Duration _h0x7e0002 = r_0x7e0000;
//// END stream content output

//// BEGIN class declarations (excluding array classes)
class org.joda.time.Duration extends org.joda.time.base.BaseDuration implements java.io.Serializable {
}

class org.joda.time.base.BaseDuration implements java.io.Serializable {
    long iMillis;
}

//// END class declarations

//// BEGIN instance dump
[instance 0x7e0002: 0x7e0000/org.joda.time.Duration
  field data:
    0x7e0001/org.joda.time.base.BaseDuration:
        iMillis: 0
    0x7e0000/org.joda.time.Duration:
]
//// END instance dump

请注意Duration的“类声明”块相当长。这也解释了为什么序列化 Duration需要107个字节,但序列化两个(不同)Duration对象只需要121个字节。

答案 1 :(得分:1)

来自the source

  

在内部,该类包含两个数据。首先,它持有   datetime为1970-01-01T00:00:00Z的Java纪元的毫秒数。   其次,它拥有一个年代表,它决定了毫秒级   即时值转换为日期时间字段。默认   年表是org.joda.time.chrono.ISOChronology,这是商定的   国际标准,与现代格里高利兼容   日历。

ISOChronology源自AssembledChronology,其中大多数(但不是全部)被声明为瞬态场。