Pregunta

Si una clase implementa la interfaz Java Serializable pero no tiene un método clone() pública, por lo general es posible crear una copia profunda de esta manera:

class CloneHelper {
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T clone(T obj) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            oos.close();
            byte[] bytes = baos.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            T copy = (T) ois.readObject();
            ois.close();
            return copy;
        } catch (ClassNotFoundException ex) {
            // Shouldn't happen
            throw new Error(ex);
        } catch (IOException ex) {
            // Probably a bug in T's custom serialization methods
            throw new RuntimeException(ex);
        }
    }
}

A menudo me encuentro clases de biblioteca de terceros como esto y recurrir a hacks como la de arriba. Incluso he ampliado ObjectOutputStream en ocasiones para hacer el más superficial de copia. Nunca ha causado problemas graves, aparte de ser ineficiente (lenta para codificar / decodificar y los gráficos de serialización temporal puede consumir una gran cantidad de memoria.)

Serializable Y si no es seguro de usar esta técnica, la clase probablemente no debería haber sido declarada.

Así que lo que me gustaría saber es, si su clase es Serializable, lo que podría impedir que la definición de un método clone() pública (mediante la interfaz Cloneable o un constructor de copia?)


Relacionado: Copiar un objeto en Java

¿Fue útil?

Solución

Bueno, estás diciendo que el mecanismo de serialización es una forma de "clon" objetos indirectamente. Esto es, por supuesto, no es su función primaria. Por lo general se utiliza para que los programas de transmisión objetos a través de una red, o tienda y más tarde los leyó. Puede que espere un objeto para ser utilizado de esta manera, e implementar Serializable, mientras no esperando código para clon de objetos a nivel local, y no aplicar Cloneable.

El hecho de que el código está trabajando en torno a este a través de la serialización sugiere el código está utilizando un objeto en una forma en que el autor no tenía la intención, lo que podría ser el autor o "fallo" de la persona que llama, pero no implica que en en general Serializable y Cloneable van de la mano.

Por otra parte, no estoy seguro de clone () está "roto" lo más difícil de implementar correctamente. Un constructor de copia es más natural a utilizar y obtener mi humilde opinión la derecha.

Otros consejos

Yo preferiría usar un constructor de copia en lugar de utilizar el mecanismo anterior. Puede más finamente definir lo que es estar profundamente o superficialmente copiado, y hacer que el copiar de un objeto distinto del serialización de un objeto. Un constructor de copia puede (por ejemplo) permiten que dos objetos que comparten una referencia a un objeto maestro, mientras que esto puede no ser apropiado para un objeto serializado y transmitida a través de la red.

Tenga en cuenta que el método Cloneable es ampliamente considerado ahora como roto. Ver este artículo con Joshua Bloch para más información. En particular, no tiene un método clone()!

punto de Brian sobre Cloneable es muy buena, pero incluso si Cloneable trabajó bien, todavía hay casos en los que es posible que desee que un objeto sea serializeable pero no cloneable.

Si un objeto tiene una identidad única fuera del alcance del proceso, como una representación en memoria de un registro de base de datos, no quiero que sea cloneable porque eso es equivalente a hacer un nuevo disco con atributos idénticos, incluidos los atributos relacionados con la identidad como la clave de la base de datos, que casi nunca es lo correcto. Al mismo tiempo, es posible que tenga un sistema dividido en varios procesos para la estabilidad o por otras razones, lo que puede tener un proceso de hablar con la base de datos y la generación de estos objetos "entidad" (Ver "Domain-Driven Design" de Eric Evans para obtener más información sobre el mantenimiento de la coherencia de la identidad del objeto en una aplicación de datos respaldados), sino un proceso separado puede utilizar estos objetos para llevar a cabo operaciones de lógica de negocio. El objeto de entidad tendría que ser serializable para que pueda ser transmitida de un proceso a otro.

Creo que las interfaces Serializable y Cloneable se deben utilizar para absolutamente diferentes propósitos. Y si usted tiene una clase compleja entonces la implementación de cada uno de ellos no es tan fácil. Por lo que en caso general que depende de los propósitos.

Uno de los mayores problemas con Serializable es que no se pueden hacer fácilmente inmutable. fuerzas de serialización que hacen un compromiso aquí.

Estaría tentado para crear constructores de copia abajo del gráfico de objetos. Es sólo un poco más ronco trabajo que hacer.

que me llama como una especie de peligrosa, ya que hay una serie de obstáculos a la serialización, (aunque la mayoría de ellos son poco probable, yo todavía quiero poner a prueba para ellos si yo estaba seria objetos en las bibliotecas del partido 3D). No es probable que sea un problema común, pero es posible tener un objeto con una variable volátil como parte de su estado que podrían ser parte de una operación de clonación (esto no es un buen diseño, sólo que es posible), y como una campo no se copian en un proceso de serialización / deserialización. Otra cuestión que viene a la mente es enumeraciones, constantes y la posibilidad de obtener múltiples copias de tales cosas si no se ocupan de ellos durante la deserialización.

Una vez más, los casos límite, pero algo que te gustaría tener en cuenta.

Yo sólo pensaba en otro caso - Cuando se trata de un enum .

O en términos más generales, cuando los implementos de marcas readResolve . Esto significa que el objeto que regrese de readObject no es el mismo que se leyó de la corriente, y por lo tanto no es necesariamente una copia del objeto que fue escrito originalmente para la corriente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top