4

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

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);
    }
}
4

2 回答 2

7

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

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

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

我已经使用jdeserialize 项目来查看序列化 ajava.util.Date与 a的结果Duration(请注意,此工具不需要访问.class文件,因此它转储的所有信息实际上都包含在序列化数据中):

结果java.util.Date

阅读:java.util.Date _h0x7e0001 = r_0x7e0000;
//// BEGIN 流内容输出
java.util.Date _h0x7e0001 = r_0x7e0000;
//// END流内容输出

//// BEGIN 类声明(不包括数组类)
类 java.util.Date 实现 java.io.Serializable {
}

//// 结束类声明

//// 开始实例转储
[实例 0x7e0001: 0x7e0000/java.util.Date
  对象注释:
    java.util.日期
        [块数据 0x00:8 字节]

  现场数据:
    0x7e0000/java.util.日期:
]
//// 结束实例转储

结果Duration

阅读:org.joda.time.Duration _h0x7e0002 = r_0x7e0000;
//// BEGIN 流内容输出
org.joda.time.Duration _h0x7e0002 = r_0x7e0000;
//// END流内容输出

//// BEGIN 类声明(不包括数组类)
类 org.joda.time.Duration 扩展 org.joda.time.base.BaseDuration 实现 java.io.Serializable {
}

类 org.joda.time.base.BaseDuration 实现 java.io.Serializable {
    长 iMillis;
}

//// 结束类声明

//// 开始实例转储
[实例 0x7e0002: 0x7e0000/org.joda.time.Duration
  现场数据:
    0x7e0001/org.joda.time.base.BaseDuration:
        伊米利斯:0
    0x7e0000/org.joda.time.Duration:
]
//// 结束实例转储

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

于 2013-09-09T14:37:38.777 回答
1

来源

在内部,该类包含两条数据。首先,它将日期时间保存为从 Java 纪元 1970-01-01T00:00:00Z 开始的毫秒数。其次,它拥有一个 Chronology,它确定如何将毫秒瞬时值转换为日期时间字段。默认的 Chronology 是 org.joda.time.chrono.ISOChronology,这是公认的国际标准,与现代公历兼容。

ISOChronology 派生自AssembledChronology,其中大部分(但不是全部)被声明为瞬态字段。

于 2013-09-09T14:19:13.367 回答