¿Por qué Java necesita una interfaz serializable?

114

Trabajamos mucho con la serialización y tener que especificar una etiqueta serializable en cada objeto que usamos es una carga. Especialmente cuando se trata de una clase de terceros que realmente no podemos cambiar.

La pregunta es: dado que Serializable es una interfaz vacía y Java proporciona una serialización robusta una vez que agrega implements Serializable, ¿por qué no hicieron que todo se serializara y eso es todo?

¿Qué me estoy perdiendo?

Yoni Roit
fuente
¿Qué pasa si desea hacer su propio objeto serializable? ¿O entendí mal algo?
Joe Phillips
Todavía obtendré NotSerializableException porque todos los campos de mis objetos tienen que ser serializables
Yoni Roit
Totalmente de acuerdo con Pop Catalin y Dmitry "Este truco serializable es solo otra decisión equivocada que se ha tomado hace una o dos décadas". No importa cuán peligrosa pueda ser la serialización. Y no es cierto que, dado que la declaración es explícita, entonces "sabes que debes prestar especial atención": todos los que lo necesitan primero ponen "implementos" y luego piensan en la implicación si algo sale mal. Podría haber sido más claro si nos dieran una interfaz "Unserializable" para aplicar en casos especiales.
Jack

Respuestas:

120

La serialización está plagada de trampas. El soporte de serialización automática de este formulario hace que las clases internas formen parte de la API pública (razón por la cual javadoc le brinda las formas persistentes de clases ).

Para la persistencia a largo plazo, la clase debe poder decodificar este formulario, lo que restringe los cambios que puede realizar en el diseño de la clase. Esto rompe la encapsulación.

La serialización también puede provocar problemas de seguridad. Al poder serializar cualquier objeto al que tenga una referencia, una clase puede acceder a datos que normalmente no podría (analizando los datos de bytes resultantes).

Hay otros problemas, como que la forma serializada de las clases internas no está bien definida.

Hacer todas las clases serializables exacerbaría estos problemas. Consulte Effective Java Second Edition , en particular, el artículo 74: Implementar serializable con criterio .

McDowell
fuente
2
Esta es claramente la mejor respuesta, estoy decepcionado de que la respuesta seleccionada no sea esta, parece que la publicación eligió con una agenda de "Estoy molesto porque tengo que declarar cosas serializables" en mente. Es un ejemplo de alguien que quiere liberar la rueda y no prestar atención a las lecciones de seguridad y diseño que ya se han aprendido en el pasado.
gbtimmon
@McDowell ¿qué quieres decir con forma persistente de clases? Seguí ese enlace pero no entiendo lo que quieres decir. ¿puedes explicar esto por favor?
Geek
@Geek: la forma serializada del tipo de URL (por ejemplo) define qué campos privados debe tener el tipo y en qué orden deben declararse.
McDowell
@McDowell ¿Por qué es importante el pedido?
Geek
12
@McDowell Hola. Soy el póster original de esta pregunta de hace 4 años, y acabo de seleccionar su respuesta como aceptada, si es que significa algo. Creo que tu respuesta es realmente la mejor, y probablemente yo era demasiado inmaduro para verlo de esa manera en ese momento. Arreglando ahora :)
Yoni Roit
32

Creo que tanto la gente de Java como la de .Net se equivocaron esta vez, habría sido mejor hacer todo serializable de forma predeterminada y solo necesitar marcar aquellas clases que no se pueden serializar de forma segura.

Por ejemplo, en Smalltalk (un lenguaje creado en los 70) cada objeto es serializable por defecto. No tengo idea de por qué este no es el caso en Java, considerando el hecho de que la gran mayoría de los objetos son seguros para serializar y solo algunos de ellos no lo son.

Marcar un objeto como serializable (con una interfaz) no hace mágicamente que ese objeto sea serializable, fue serializable todo el tiempo , es solo que ahora expresaste algo que el sistema podría haber encontrado por sí mismo, así que no veo una buena razón para ello. la serialización es como está ahora.

Creo que fue una mala decisión tomada por los diseñadores o la serialización fue una ocurrencia tardía, o la plataforma nunca estuvo lista para realizar la serialización por defecto en todos los objetos de manera segura y consistente.

Pop Catalin
fuente
26
Debe tener especial cuidado al diseñar e implementar una clase para asegurarse de que las instancias se serialicen de manera sensata. La interfaz serializable en realidad significa: "Yo, como programador, he entendido las consecuencias de la serialización y permito que la JVM
serialice
@Rolf Rander: la mayoría de las veces no necesita tener ningún cuidado, solo marque la clase como serializable. Si la serialización hubiera estado ACTIVADA por defecto en todos los objetos, la mentalidad de cada desarrollador también habría sido diferente, habría sido algo natural hacer una clase serializable ...
Pop Catalin
habría agregado otra preocupación a la lista de buen diseño de clase, como por ejemplo, asegurarse de que no tenga pérdidas de memoria. Aún así, un buen diseño de clases requiere cada vez más que sus clases sean serializables cuando pueden.
Pop Catalin
3
@StaxMan, porque darse cuenta más tarde de que necesita serializar una clase y no puede, puede ser muy costoso. Es uno de esos casos en los que vale la pena realizar un pequeño esfuerzo adicional. Esto es especialmente cierto si está escribiendo una biblioteca y alguien más la consumirá sin el código fuente
Pop Catalin
2
Estoy completamente de acuerdo con esta respuesta. En muchos idiomas, todo es serializable por defecto. Y en realidad lo mismo con JVM, porque es fácil de usar Reflection para acceder a cualquier miembro de la clase, ya sea privado o no. Este Serializabletruco es solo otra decisión incorrecta que se tomó hace una o dos décadas, y una adición más a la molestia cuando se trata de Java puro, como algunas fallas en la colección y el procesamiento de cadenas en la biblioteca estándar. Felizmente está Kryo, pero es dependencia y hay que encontrarlo primero. Así es como debería haberse realizado la serialización integrada.
dmitry
20

No todo es genuinamente serializable. Tome una conexión de red, por ejemplo. Puede serializar los datos / estado de su objeto de socket, pero la esencia de una conexión activa se perdería.

Joel Coehoorn
fuente
Este sería mi problema y si no fuera lo suficientemente inteligente como para intentar serializar el socket, encontraría mi error durante la depuración. Sin embargo, ahora estoy en una situación en la que no puedo usar la serialización de Java debido a una clase de terceros que no implementa Serializable sin una buena razón.
Yoni Roit
4
Hay algunas formas decentes de manejar este caso, como escribir una clase contenedora serializable que sepa leer y escribir los datos clave de la clase de terceros; haga que la instancia envuelta sea transitoria y anule writeObject y readObject.
Greg Case
¿Puede heredar de los objetos requeridos en su api y serializar esas clases?
Joel Coehoorn
@Joel: Es una buena idea, pero sigue siendo un truco. Supongo que todo esto es solo otra compensación que salió mal. Gracias por tus comentarios.
Yoni Roit
1
Este es uno de esos raros ejemplos que ilustra que todo lo que realmente necesitamos es implements NotSerializable:)
Rob Grant
13

La función principal de Serializable en Java es hacer, de forma predeterminada, todos los demás objetos no serializables. La serialización es un mecanismo muy peligroso, especialmente en su implementación predeterminada. Por lo tanto, al igual que la amistad en C ++, está desactivada de forma predeterminada, incluso si cuesta un poco hacer que las cosas sean serializables.

La serialización agrega restricciones y problemas potenciales ya que la compatibilidad de la estructura no está asegurada. Es bueno que esté desactivado por defecto.

Debo admitir que he visto muy pocas clases no triviales en las que la serialización estándar hace lo que yo quiero. Especialmente en el caso de estructuras de datos complejas. Por lo tanto, el esfuerzo que dedicaría a hacer que la clase se serializara adecuadamente eclipsa el costo de agregar la interfaz.

Uri
fuente
9

Para algunas clases, especialmente aquellas que representan algo más físico como un archivo, un socket, un hilo o una conexión de base de datos, no tiene ningún sentido serializar instancias. Para muchos otros, la serialización puede ser problemática porque destruye las restricciones de unicidad o simplemente lo obliga a lidiar con instancias de diferentes versiones de una clase, lo que quizás no desee.

Podría decirse que podría haber sido mejor hacer que todo se serializara de forma predeterminada y que las clases no se serializaran a través de una interfaz de palabra clave o marcador, pero aquellos que deberían usar esa opción probablemente no pensarían en ello. Tal como está, si necesita implementar Serializable, una Excepción se lo dirá.

Michael Borgwardt
fuente
4

Creo que la idea fue asegurarse de que usted, como programador, sepa que su objeto puede ser serializado.

Milhous
fuente
1

Tener que declarar explícitamente que las instancias de una determinada clase son serializables, el lenguaje te obliga a pensar si debes permitir eso. Para objetos de valor simple, la serialización es trivial, pero en casos más complejos es necesario pensar realmente las cosas.

Con solo confiar en el soporte de serialización estándar de la JVM, se expone a todo tipo de problemas desagradables de versiones.

La singularidad, las referencias a recursos "reales", temporizadores y muchos otros tipos de artefactos NO son candidatos para la serialización.

Jeroen van Bergen
fuente
0

Bueno, mi respuesta es que esto no es por una buena razón. Y por sus comentarios puedo ver que ya lo aprendió. Otros lenguajes intentan felizmente serializar todo lo que no salta en un árbol después de haber contado hasta 10. Un Objeto debe ser serializable por defecto.

Entonces, lo que básicamente debe hacer es leer todas las propiedades de su clase de terceros usted mismo. O, si esa es una opción para usted: descompilar, poner la maldita palabra clave allí y volver a compilar.

nes1983
fuente
2
La serialización agrega restricciones y problemas potenciales ya que la compatibilidad de la estructura no está asegurada. En mi humilde opinión, es bueno que esté desactivado de forma predeterminada.
Uri
No estoy seguro de lo que quiere decir con "compatibilidad de estructura".
nes1983
0

Hay algunas cosas en Java que simplemente no se pueden serializar porque son específicas del tiempo de ejecución. Cosas como transmisiones, subprocesos, tiempo de ejecución, etc. e incluso algunas clases de GUI (que están conectadas al sistema operativo subyacente) no se pueden serializar.


fuente
0

Si bien estoy de acuerdo con los puntos mencionados en otras respuestas aquí, el problema real es con la deserialización: si la definición de la clase cambia, existe un riesgo real de que la deserialización no funcione. ¡Nunca modificar campos existentes es un compromiso bastante importante para el autor de una biblioteca! Mantener la compatibilidad con la API ya es bastante complicado.

CortinaPerro
fuente
Esto no es correcto. Debe leer el capítulo Control de versiones de objetos serializables de la Especificación de serialización de objetos, que no existiría si lo que afirma aquí fuera cierto. La definición de clase puede cambiar dentro de límites bastante amplios antes de que se vuelva incompatible con serializaciones anteriores. Y ciertamente no es la respuesta a la pregunta. La verdadera razón tiene que ver con las preocupaciones de seguridad.
Marqués de Lorne
@EJP, en aras de la veracidad, he editado mi respuesta para reflejar sus puntos. Sin embargo, el sentimiento se mantiene, es un gran compromiso que definitivamente debería ser opt-in en lugar de opt-out
CurtainDog
0

Una clase que debe conservarse en un archivo u otro medio tiene que implementar una interfaz serializable, de modo que JVM pueda permitir que el objeto de la clase sea serializado. Por qué la clase Object no está serializada, entonces ninguna de las clases necesita implementar la interfaz, después de todo, JVM serializa la clase solo cuando uso ObjectOutputStream, lo que significa que el control todavía está en mis manos para permitir que la JVM se serialice.

La razón por la que la clase Object no se puede serializar de forma predeterminada es el hecho de que la versión de la clase es el problema principal. Por lo tanto, cada clase que esté interesada en la serialización debe marcarse como serializable explícitamente y proporcionar un número de versión serialVersionUID.

Si no se proporciona serialVersionUID , obtenemos resultados inesperados al deserializar el objeto, es por eso que JVM arroja InvalidClassException si serialVersionUID no coincide. Por lo tanto, cada clase tiene que implementar una interfaz serializable y proporcionar serialVersionUID para asegurarse de que la clase presentada en ambos extremos sea idéntica.

Trinesh Andhurthi
fuente