2009-06-17 13 views

Respuesta

18

La primera pregunta es ¿por qué necesita serializar los miembros estáticos?

Los miembros estáticos están asociados a la clase, no a las instancias, por lo que no tiene sentido incluirlos al serializar una instancia.

La primera solución es hacer que esos miembros no sean estáticos. O bien, si esos miembros son los mismos en la clase original y la clase objetivo (misma clase, pero posiblemente en entornos de tiempo de ejecución diferentes), no los serialice en absoluto.

Tengo algunas ideas sobre cómo se puede enviar a través de miembros estáticos, pero primero necesito ver el caso de uso, como en todos los casos eso significa actualizar la clase objetivo, y no he encontrado una buena razón para hacerlo asi que.

+2

supongamos que quiero contar el número de instancia de una clase como Coche. y no estoy usando la base de datos. Así, en ese caso, después del cierre de la aplicación, debo almacenar esta información con otra información. –

+4

¿Necesita almacenar ese número directamente? Si actualiza el número a medida que deserializa cada automóvil (anulando readObject), reflejará correctamente el número de autos en la serialización. –

+0

Las variables estáticas se comparten entre todas las instancias de los objetos de una clase (memoria compartida). Si necesita guardar algo estático, como si tuviera una enumeración de valores diferentes y de vez en cuando cambiara un valor estático de ese tipo de enumeración, cambiar el valor guardado podría ser tan simple como tener todas las clases configuradas como variables locales a ese tipo.O podría dar un paso más, y tener un grupo de clases ampliar la clase Lo que sea, y la clase Lo que sea, podría simplemente compartir una variable local para todos sus hijos. Cuando se deserialice, puede volver a cargar sus valores estáticos como estaban. –

2

Los miembros estáticos pertenecen a la clase, no a los objetos individuales.

Debe reconsiderar su estructura de datos.

5

Puede controlar la serialización implementando:

private void writeObject(ObjectOutputStream out) throws IOException; 

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException; 

Hay una descripción completa de serialización http://java.sun.com/developer/technicalArticles/Programming/serialization/.

Como han dicho otras respuestas, realmente no tiene sentido serializar statics ya que es el objeto, no la clase que está serializando y necesita hacer, huele como si tuviera otros problemas con su código para mí.

+0

Puede controlar la serialización, pero no hay ningún lugar sensato para poner datos estáticos porque no tiene ningún sentido en el contexto. –

+0

Dado que no conocemos el contexto, no podemos decir si tiene sentido o no. Por ejemplo, después de usar la serialización predeterminada, podría tener sentido agregar el miembro estático a la transmisión. En la deserialización, uno puede establecer el miembro estático si es nulo; de lo contrario, descarte el objeto serializado. – erickson

+0

Tom, estás abusando de "prueba por repetición", ¿verdad? ;) –

2

Buenas respuestas y comentarios - no lo hagas. ¿Pero cómo?

Lo más probable es que esté creando un objeto para contener todas sus "Estáticas". Ese objeto probablemente también tenga métodos estáticos de tu clase.

Cada instancia de su clase puede contener esta otra clase, o si realmente tiene que hacerlo, puede convertirlo en un singleton al que cualquier miembro puede acceder.

Después de hacer este refactorizador, encontrará que debería haberlo hecho así todo el tiempo. Incluso puede descubrir que algunas de sus limitaciones de diseño previas que lo estaban molestando en un nivel de subconcesamiento se han desvanecido.

Probablemente descubrirá que esta solución también resuelve otros problemas de serialización que aún no había notado.

14

Gente, estática no significa INMUTABLE. Por ejemplo, es posible que desee serializar todo el estado del cálculo (sí, incluidos los campos estáticos, contadores, etc.) para reanudarlo más tarde, después de reiniciar JVM y/o la computadora host.

La respuesta correcta a eso, como ya se dijo, es usar interfaz Externalizable, no Serializable. Entonces tienes un control completo sobre qué y cómo externalizas.

+1

Si el estado del cálculo no está incrustado en el objeto que está serializando, entonces no debería almacenarlo como parte de la serialización de ese objeto. – DJClayworth

+3

Mutable static generalmente significa roto. –

+1

Piense de nuevo. ¿Qué hay de los algoritmos genéticos multiproceso, por ejemplo? El almacenamiento compartido (estático) se usa para mantener el registro de las variantes evaluadas. Que sea un singleton? Posible, pero tiene sus propios inconvenientes. –

0

Sí, podemos serializar las variables estáticas. Pero podemos escribir nuestro propio writeObject() y readObject(). Creo que esto puede resolver el problema.

0

Tener aplicación compacta, implementar readObject & writeObject en su llamada clase defaultReadObject & métodos defaultWriteObject dentro de esos métodos que maneja la serialización normal y luego proceder con la serialización & de-serialización lo que necesita campos adicionales.

Saludos, GK

5

Ésta es la serialización para el campo estático: newBookingNumber.

class Booking implements Serializable 
{ 

    /** 
    * Generated serial version ID. 
    */ 

    private static final long serialVersionUID = 5316748056989930874L; 

    // To hold new booking number. 
    private static int newBookingNumber = 0; 

    // The booking number. 
    private int bookingNumber; 


    /* 
    * Default serializable fields of a class are defined to be 
    * the non-transient and non-static fields. So, we have to 
    * write and read the static field separately. 
    */ 
    private void writeObject(ObjectOutputStream oos) 
     throws IOException 
    { 
     oos.defaultWriteObject(); 
     oos.writeObject(new Integer(newBookingNumber)); 
    } 

    private void readObject(ObjectInputStream ois) 
    throws ClassNotFoundException, IOException 
    { 
     ois.defaultReadObject(); 
     newBookingNumber = (Integer)ois.readObject(); 
    } 
} 
2

Usted puede hacer esto sin tener que actualizar manualmente su clase cada vez que se cambia simplemente un campo. Es posible que desee hacer esto si desea tener la facilidad de los miembros estáticos para acceder a la configuración en una aplicación, pero también desea guardar esa configuración. En este caso, también desearía tener la opción de aplicarlos a su antojo, no cargarlos de manera predeterminada ya que las otras soluciones aquí lo requieren, ya que son estáticos. Esto permite la reversión de configuraciones por razones obvias.

Básicamente, utilice los métodos de campo para obtener todos los miembros de la clase, luego asigne los nombres completos de estos campos a los contenidos. El nombre completo es obligatorio ya que Field no es serializable. Serialice esta asignación y vuelva a instalarla para obtener la configuración guardada.

La segunda parte del rompecabezas es el tipo de función apply(). Esto pasa por la asignación y aplica lo que puede a la clase estática.

También debe asegurarse de que los contenidos de los miembros estáticos sean ellos mismos serializables.

Como se puede ver con suerte en esta clase de ejemplo, los miembros estáticos se pueden guardar y devolver fácilmente. Dejaré que el implementador se preocupe por los UID de las clases, las salvaguardas, etc. isSameAs() se usa para las pruebas unitarias. AppSettings es la clase que contiene todos los campos estáticos que desea serializar.

public class AppSettingsReflectorSaver implements Serializable { 

HashMap<String, Object> genericNamesAndContents = new HashMap<String, Object>(); 
private AppSettingsReflectorSaver() { 
} 

static AppSettingsReflectorSaver createAppSettingsSaver() { 
    AppSettingsReflectorSaver ret = new AppSettingsReflectorSaver(); 
    ret.copyAppSettings(); 
    return ret; 
} 

private void copyAppSettings() { 
    Field[] fields = AppSettings.class.getFields(); 
    for (Field field : fields) { 
     mapContentsForSerialization(field); 
    } 
} 

private void mapContentsForSerialization(Field field) { 
    try { 
     Object fieldContents = field.get(AppSettings.class); 
     genericNamesAndContents.put(field.toGenericString(), fieldContents); 
    } catch (IllegalArgumentException ex) { 
     Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex); 
    } catch (IllegalAccessException ex) { 
     Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex); 
    } 
} 

boolean isSameAs(AppSettingsReflectorSaver now) { 
    for(String thisKey : genericNamesAndContents.keySet()){ 
     boolean otherHasThisKey = now.genericNamesAndContents.containsKey(thisKey); 
     Object thisObject = genericNamesAndContents.get(thisKey); 
     Object otherObject = now.genericNamesAndContents.get(thisKey); 
     boolean otherHasThisValue = thisObject.equals(otherObject); 
     if (!otherHasThisKey || !otherHasThisValue){ 
      return false; 
     } 
    } 
    return true; 
} 

void applySavedSettingsToStatic() { 
    Field[] fields = AppSettings.class.getFields(); 
    for (Field field : fields) { 
     if (!genericNamesAndContents.containsKey(field.toGenericString())){ 
      continue; 
     } 
     Object content = genericNamesAndContents.get(field.toGenericString()); 
     try { 
      field.set(AppSettings.class, content); 
     } catch (IllegalArgumentException ex) { 
      Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex); 
     } catch (IllegalAccessException ex) { 
      Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
} 

}

Este es mi primer post - ir fácil en mí: P ~

Cuestiones relacionadas