我想指出,在比较Serializable
和Externalizable
方法时还有其他优点/缺点需要考虑。
外化更快
在序列化期间,JVM 将始终首先检查该类是否是 Externalizable。如果是这种情况,那么它将使用这些read/writeExternal
方法。(有道理,对)
可外部化的类需要较少的递归,因为您可以精确地识别您需要的数据。它还导致更紧凑的输出(更少的字节),这将我们带到了下一点......
外化输出更紧凑
如果您比较实际输出,它看起来像这样:对象的标头包含一个标志,该标志标记该类是 justSerializable
还是 may also Externalizable
。
OBJECT
CLASSDESC
Class Name: "MyClassName"
Class UID: ...
Class Desc Flags: SERIALIZABLE or EXTERNALIZABLE
如果它只是SERIALIZABLE
,那么将跟随一个字段列表(如定义),然后是实际数据。这对每个序列化对象重复。
Field Count: ...
// followed by an bunch of declarations of objects
Field type: object
Field name: "fieldName"
Class name: "Ljava/lang/String;"
// followed by the actual data
STRING: "foo"
STRING: "bar"
float: 123456
Externalizable 对象不包含字段和数据的列表,它们仅包含按您保存的顺序编码的数据。
EXTERNALIZABLE: [00 AA 00 BC ... ]
外化更灵活
如果您保存购物清单,那么您只需要产品名称,对吗?
public class ShoppingList implements Externalizable {
String name;
List<Product> productList;
@Override
public void writeExternal(ObjectOutput pOutput) throws IOException
{
out.writeUTF(name);
for (Product product : productList)
{
// save only product id
out.writeUTF(product.getEanCode());
}
}
...
}
但是,如果您要结帐,那么您也想节省价格,对吗?
public class Bill implements Externalizable {
String name;
List<Product> productList;
@Override
public void writeExternal(ObjectOutput pOutput) throws IOException
{
out.writeUTF(name);
for (Product product : productList)
{
// save product id and price
out.writeUTF(product.getEanCode());
out.writeInt(product.getPrice());
}
}
...
}
So, in some cases the price is transient and in some cases it is not. How would you solve this with the transient
keyword ? -- I will let you figure this one out. This kind of flexibility is really missing when using only the transient keyword.
Design considerations
However, there are some dangers as well. Externalizable objects can only be implemented for objects with a public default constructor (a public constructor without arguments).
That makes it impossible to make non-static inner classes Externalizable
. The problem is that JVM modifies the constructors at runtime, and adds a reference to the parent class during compilation. So you cannot have a default no-argument constructor for a non-static inner class.
You also have to consider the possibility of modifying your object in future (e.g. adding non-transient fields). Serializable classes could have backwards compatibility issues, but don't require code changes per se. Externalizable classes will require a code change in your read/write method, but have more options to handle compatibility issues.
Just one more thing. If you are chosing this "technology" to communicate between different applications, then please just don't. What you want is JAXB. It's less compact, but more transparent, no compatibility issues, and just as flexible.
Hidden features
Just to be complete, there is one more thing which makes this topic a bit more complicated. It's actually possible to use read/write methods without using the Externalizable
interface at all. Before Externalizable
was introduced, it was possible to define private writeObject
and readObject
methods. But really, you shouldn't use that method anymore.