【问题标题】:Java: efficiency of writeObject vs writeExternalJava:writeObject 与 writeExternal 的效率
【发布时间】:2012-05-13 17:02:38
【问题描述】:

据说Java的默认序列化机制效率不高,因为a)它通过通常很慢的反射发现要写入/读取的字段b)它将额外的数据写入流。

提高效率的一种方法是实现 Externalizable 及其 writeExternal/readExternal 方法。

问题来了:如果我改为提供 'writeObject/readObject' 方法并且不在其中调用 deafiltWriteObject/defaultReadObject,那么此机制将不会使用反射来确定要写入/读取的字段,而且它不会' t 将额外的数据写入流(或者会不会?不确定)。那么从效率的角度来看,实现上面提到的 writeObject/readObject 是否与实现 Externalizable 相同?或者后一种选择是否提供了一些更实际的好处,而前者没有?

编辑:当然,不同的是,当实现 readObject/writeObject 的 Serializable 类被子类化时,如果子类有自己的 readObject/writeObject,则不需要调用 super 的 readObject/writeObject。如果超类/子类改为实现 Externalizable,则不是这样。在这种情况下,super 的 writeExternal/readExternal 需要显式调用。 但是,从效率的角度来看,这种差异是无关紧要的。

【问题讨论】:

  • 我可以知道您是如何得出在可序列化类中不需要 super.readObject() 的结论的吗?这是否意味着对于每个读/写 Object 方法,编译器都会在第一行添加对 defaultread/writeObject() 方法的调用?
  • @amarnath harish,我相信编译器添加了对 super 的读/写对象的调用。您可以编写一个小代码 sn -p 来验证这一点。 PL。如果您发现其他情况,请告诉我。

标签: java serialization


【解决方案1】:

在选择接下来要调用哪个类/writeObject/readObject 方面仍有一些开销。但明显减少了。

这可以执行与 Externalizable 相同的操作,具体取决于您正在做什么以及您是否使用它为您提供的额外选项。例如readObject 假设您每次都创建一个新对象,Externalizable 具有 readResolve 意味着您可以重用对象。

http://docs.oracle.com/javase/1.5.0/docs/guide/serialization/spec/input.html

在许多情况下,回收对象是加速反序列化的“下一步”。 (假设这是您的选择)

http://vanillajava.blogspot.co.uk/2011/10/recycling-objects-to-improve.html

【讨论】:

  • 您能请教一下吗?再解释一下:“在选择接下来要调用哪个类/writeObject/readObject 方面仍有一些开销。”另外,“readResolve”不是“Externalizable”合约的一部分,对吧?所以我有点困惑。
  • 它必须确定调用哪个类 readObject 或 readExternal ,除非您自己也这样做。 readResolve 是一种可选方法,您也可以将其与 Serrailizable 一起使用。有关详细信息,请参阅第一个链接。
  • 谢谢。我使用过 readResolve,但因为您提到它与 Externalizable 相关而感到困惑。顺便说一句,我读了你的文章。好一个。我在那里问了一个问题。如果你能请,那就太好了。回复。
【解决方案2】:

在试验和浏览序列化机制的代码时发现了一些东西:

1) 如果发现对象是Externalizable,则将其强制转换为Externalizable,并在其上调用相应的方法;而对于可序列化对象,它会反射性地检查它是否具有 readObject/writeObject。所以也许这会让它稍微慢一点,

2) Externalizable 写入的数据量比使用 readObject/writeObject 的 Serializable 略少(我在写 B 的对象时发现以下代码有 1 个字节的差异)。

对于外部化:

static class A implements Externalizable
{
    @Override
    public void writeExternal(ObjectOutput out) throws IOException 
    {
        System.out.println("A write called");
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException 
    {
        System.out.println("A read called");
    }       
}

static class B extends A implements Externalizable
{       
    @Override
    public void writeExternal(ObjectOutput out) throws IOException 
    {
        super.writeExternal(out);
        System.out.println("B write called");
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException 
    {
        super.readExternal(in);
        System.out.println("B read called");
    }       
}

对于可序列化:

static class A implements Serializable
{
    private void writeObject(ObjectOutputStream out) throws IOException 
    {
        System.out.println("A write called");
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException 
    {
        System.out.println("A read called");
    }       
}

static class B extends A implements Serializable
{       
    private void writeObject(ObjectOutputStream out) throws IOException 
    {           
        System.out.println("B write called");
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException 
    {           
        System.out.println("B read called");
    }       
}

【讨论】:

    【解决方案3】:

    在类设计方面的主要区别在于,Serializable 将适用于任何类,而 Externalizable 仅适用于具有公共默认(无参数)构造函数的可变类。

    【讨论】:

    • 它们真的需要可变吗?我的意思是,我不能做这样的事情吗? byteslounge.com/tutorials/java-externalizable-example
    • @shrini1000,你可以这样做,但 User 类不是线程安全的。但是,将所有字段设置为 volatile 应该可以解决这个问题,所以最后,您是对的,严格来说,该类不必是可变的。
    猜你喜欢
    • 1970-01-01
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多