2012-05-04 14 views
16

Se dice que el mecanismo de serialización predeterminado de Java no es muy eficiente porque a) descubre qué campos escribir/leer mediante reflexión, que suele ser lento b) escribe datos adicionales en la transmisión.Java: eficacia de writeObject vs writeExternal

Una forma de hacerlo más eficiente es implementar Externalizable y sus métodos writeExternal/readExternal.

Aquí está la pregunta: si en cambio proporciono los métodos 'writeObject/readObject' y no llamo a deafiltWriteObject/defaultReadObject en ellos, entonces este mecanismo no usará la reflexión para descubrir qué campos escribir/leer, más lo ganó No escriba datos adicionales para transmitir (¿o no? seguro). Entonces, desde una perspectiva de eficiencia, ¿está implementando writeObject/readObject mencionado arriba como implementación de Externalizable? ¿O la última opción ofrece algunos beneficios más prácticos que los anteriores no?

EDITAR: una diferencia, por supuesto, es cuando una clase Serializable que implementa readObject/writeObject está subclasificada, y si la subclase tiene su propio readObject/writeObject, no necesitan llamar a readObject/writeObject de super. No es así si la súper/subclase en su lugar implementa Externalizable. En este caso, es necesario llamar explícitamente a super's writeExternal/readExternal. Sin embargo, esta diferencia es irrelevante desde el punto de vista de la eficiencia.

Respuesta

7

Todavía hay un exceso de decisión al elegir qué clase/writeObject/readObject llamar a continuación. pero se reduce significativamente.

Esto puede realizar lo mismo que Externalizable dependiendo de lo que esté haciendo y si usa las opciones adicionales que le ofrece. p.ej. readObject asume que debes crear un nuevo objeto cada vez. Externalizable tiene readResolve, lo que significa que puedes reutilizar objetos.

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

En muchos casos, los objetos de reciclaje es el "siguiente" paso en la aceleración de deserialización. (Asumiendo que es una opción para usted)

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

+0

¿Podría usted pl. explique esto un poco más: "Todavía hay un exceso de decisión al elegir qué clase/writeObject/readObject llamar a continuación". Además, 'readResolve' no es parte del contrato 'Externalizable', ¿verdad?Entonces estoy un poco confundido. – shrini1000

+0

Tiene que determinar qué clase llamar readObject o readExternal a menos que también lo hagas tú mismo. readResolve es un método opcional que puedes usar también con Serailizable. Vea el primer enlace para más detalles. –

+1

Thx. He usado readResolve, pero me confundí porque lo mencionaste en relación con Externalizable. Por cierto, leí tu artículo. Buena persona He hecho una pregunta allí. Sería genial si pudieras. respuesta. – shrini1000

1

encontramos un par de cosas mientras que la experimentación y pasando por el código del mecanismo de serialización:

1) si el objeto se encuentra para ser Externalizable, se echó a Externalizable , y se le llama al método correspondiente; mientras que para el objeto Serializable, se verifica reflexivamente si tiene readObject/writeObject. Así que tal vez esto lo hace un poco más lento,

2) la cantidad de datos escritos para Externalizable es un poco menor que Serializable con readObject/writeObject (encontré una diferencia de 1 byte para el siguiente código cuando escribí el objeto de B) .

Para Externalizable:

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

Para Serializable:

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"); 
    }  
} 
2

La principal diferencia, en términos de diseño de clase, es que Serializable funcionará en cualquier clase, mientras que Externalizable sólo funciona en clases mutables con constructores públicos por defecto (no-arg).

+0

¿Realmente necesitan ser mutables? Quiero decir, ¿no puedo hacer algo como esto? http://www.byteslounge.com/tutorials/java-externalizable-example – shrini1000

+0

@ shrini1000, podrías hacerlo, pero la clase 'User' no es segura para subprocesos. Sin embargo, hacer que todos los campos sean "volátiles" debería arreglar eso, así que al final, tienes razón, la clase no tiene que ser, en sentido estricto, mutable. – nilskp