Por que o Java precisa de uma interface serializável?

114

Trabalhamos intensamente com serialização e ter que especificar a tag Serializable em cada objeto que usamos é meio que um fardo. Especialmente quando é uma aula de terceiros que não podemos realmente mudar.

A questão é: já que Serializable é uma interface vazia e o Java fornece serialização robusta quando você adiciona implements Serializable- por que eles não tornaram tudo serializável e é isso?

o que estou perdendo?

Yoni Roit
fonte
E se você quiser tornar seu próprio objeto serializável? Ou eu entendi mal alguma coisa?
Joe Phillips
Ainda receberei NotSerializableException porque todos os campos dos meus objetos devem ser serializáveis
Yoni Roit
Concordo totalmente com Pop Catalin e dmitry "Este truque serializável é apenas mais uma decisão errada que foi tomada há uma ou duas décadas". Não importa o quão perigosa pode ser a serialização. E não é verdade que, como a declaração é explícita, então "você sabe que precisa prestar atenção especial": todos que precisam primeiro colocam as coisas "implementam" e, em seguida, pensam na implicação se algo der errado. Poderia ter sido mais claro se eles nos dessem uma interface "Não serializável" para ser aplicada em casos especiais.
Jack

Respostas:

120

A serialização está repleta de armadilhas. O suporte de serialização automática deste formulário torna a parte interna da classe da API pública (é por isso que o javadoc fornece as formas persistentes de classes ).

Para persistência de longo prazo, a classe deve ser capaz de decodificar essa forma, o que restringe as alterações que você pode fazer no design da classe. Isso quebra o encapsulamento.

A serialização também pode levar a problemas de segurança. Por ser capaz de serializar qualquer objeto ao qual tenha uma referência, uma classe pode acessar dados que normalmente não seria capaz (analisando os dados de byte resultantes).

Existem outros problemas, como a forma serializada das classes internas não ser bem definida.

Tornar todas as classes serializáveis ​​exacerbaria esses problemas. Confira Effective Java Second Edition , em particular o Item 74: Implementar Serializable judiciosamente .

McDowell
fonte
2
Esta é claramente a melhor resposta, estou desapontado que a resposta selecionada não seja esta, parece que o postado escolheu com uma agenda "Estou chateado porque tenho que declarar coisas serializáveis" em mente. É um exemplo de alguém que quer liberar e não dar atenção às lições de segurança e design que já foram aprendidas no passado.
gbtimmon
@McDowell o que você quer dizer com forma persistente de classes? Eu segui esse link, mas não consigo entender o que você quer dizer? você pode explicar isso por favor?
Geek
@Geek - A forma serializada do tipo de URL (por exemplo) define quais campos privados o tipo deve ter e em que ordem eles devem ser declarados.
McDowell
@McDowell Por que o pedido é importante?
Geek de
12
@McDowell Olá. Sou o autor desta pergunta há 4 anos e acabei de selecionar sua resposta como aceita, se isso significar alguma coisa. Acho que sua resposta é realmente a melhor, e provavelmente eu era muito imaturo para ver dessa forma na época. Corrigindo agora :)
Yoni Roit
32

Acho que tanto o pessoal do Java quanto do .Net erraram desta vez, teria sido melhor tornar tudo serializável por padrão e apenas precisar marcar as classes que não podem ser serializadas com segurança.

Por exemplo, em Smalltalk (uma linguagem criada nos anos 70), todo objeto é serializável por padrão. Não tenho ideia de por que esse não é o caso em Java, considerando o fato de que a grande maioria dos objetos é segura para serializar e apenas alguns deles não.

Marcar um objeto como serializável (com uma interface) não torna esse objeto magicamente serializável, ele era serializável o tempo todo , só que agora você expressou algo que o sistema poderia ter encontrado por conta própria, então não vejo um bom motivo para serialização sendo do jeito que está agora.

Acho que foi uma má decisão dos designers ou a serialização foi uma reflexão tardia, ou a plataforma nunca estava pronta para fazer a serialização por padrão em todos os objetos de forma segura e consistente.

Pop Catalin
fonte
26
Você precisa ter um cuidado especial ao projetar e implementar uma classe para garantir que as instâncias sejam serializadas de forma sensata. A interface serializável realmente significa: "Eu, como um programador, entendi as consequências da serialização e permiti que a JVM serializasse isso"
Rolf Rander
@Rolf Rander: na maioria das vezes você não precisa tomar nenhum cuidado, apenas marcar a classe serializável. Se a serialização estivesse ATIVADA por padrão em todos os objetos, a mentalidade de cada desenvolvedor também teria sido diferente, teria sido algo natural fazer uma classe serializável ...
Pop Catalin
isso teria adicionado outra preocupação à lista de bons designs de classe, como, por exemplo, certificar-se de que você não tem vazamentos de memória. Ainda assim, um bom design de classe cada vez mais requer que suas classes sejam serializáveis ​​quando possível.
Pop Catalin de
3
@StaxMan, porque perceber mais tarde que você precisa serializar uma classe e não pode, pode ser muito caro. É um daqueles casos em que pouco esforço extra compensa. Isso é especialmente verdadeiro se você estiver escrevendo uma biblioteca e outra pessoa a consumir sem o código-fonte
Pop Catalin
2
Eu concordo totalmente com esta resposta. Em muitos idiomas, tudo é serializável por padrão. E na verdade o mesmo com a JVM, porque é fácil usar o Reflection para acessar qualquer membro da classe, seja ela privada ou não. Esse Serializabletruque é apenas mais uma decisão errada que foi tomada há uma ou duas décadas, e mais um acréscimo ao aborrecimento ao lidar com java puro, como algumas falhas no processamento de coleção e string na biblioteca padrão. Felizmente existe Kryo, mas é uma dependência e é preciso encontrá-lo primeiro. É assim que a serialização interna deveria ter sido feita.
dmitry
20

Nem tudo é genuinamente serializável. Considere uma conexão de soquete de rede, por exemplo. Você poderia serializar os dados / estado de seu objeto de soquete, mas a essência de uma conexão ativa seria perdida.

Joel Coehoorn
fonte
Esse seria o meu problema e se eu não fosse inteligente o suficiente para tentar serializar o soquete, encontraria meu erro durante a depuração. No entanto, agora estou em uma situação em que não posso usar a serialização Java por causa da classe de terceiros que não implementa Serializable sem um bom motivo.
Yoni Roit
4
Existem algumas maneiras decentes de lidar com esse caso, como escrever uma classe de wrapper Serializable que sabe como ler e gravar os dados-chave da classe de terceiros; tornar a instância encapsulada transitória e substituir writeObject e readObject.
Greg Case
Você pode herdar dos objetos necessários em sua API e serializar essas classes?
Joel Coehoorn
@Joel: É uma boa ideia, mas ainda assim um hack. Acho que tudo isso é apenas mais uma troca que deu errado. Obrigado por seus comentários.
Yoni Roit
1
Este é um daqueles raros exemplos que ilustram que tudo o que realmente precisamos é implements NotSerializable:)
Rob Grant
13

A principal função do Serializable em Java é tornar, por padrão, todos os outros objetos não serializáveis. A serialização é um mecanismo muito perigoso, especialmente em sua implementação padrão. Conseqüentemente, como a amizade em C ++, ele está desativado por padrão, mesmo que custe um pouco para tornar as coisas serializáveis.

A serialização adiciona restrições e problemas potenciais, uma vez que a compatibilidade da estrutura não é garantida. É bom que esteja desativado por padrão.

Tenho que admitir que vi muito poucas classes não triviais onde a serialização padrão faz o que eu quero. Especialmente no caso de estruturas de dados complexas. Portanto, o esforço que você gastaria para tornar a classe serializável de maneira adequada diminui o custo de adicionar a interface.

Uri
fonte
9

Para algumas classes, especialmente aquelas que representam algo mais físico como um arquivo, um soquete, um thread ou uma conexão de banco de dados, não faz absolutamente nenhum sentido serializar instâncias. Para muitos outros, a serialização pode ser problemática porque destrói as restrições de exclusividade ou simplesmente força você a lidar com instâncias de diferentes versões de uma classe, o que você pode não querer.

Indiscutivelmente, poderia ter sido melhor tornar tudo Serializável por padrão e tornar as classes não serializáveis ​​por meio de uma palavra-chave ou interface de marcador - mas então, aqueles que deveriam usar essa opção provavelmente não pensariam sobre isso. Do jeito que está, se você precisar implementar Serializable, será informado por uma Exceção.

Michael Borgwardt
fonte
4

Acho que o pensamento era garantir que você, como programador, saiba que seu objeto pode ser serializado.

Milhous
fonte
1

Ter que declarar explicitamente que as instâncias de uma determinada classe são serializáveis, a linguagem força você a pensar se deve permitir isso. Para objetos de valor simples, a serialização é trivial, mas em casos mais complexos você precisa realmente pensar sobre as coisas.

Contando apenas com o suporte de serialização padrão da JVM, você se expõe a todos os tipos de problemas desagradáveis ​​de versão.

Exclusividade, referências a recursos 'reais', temporizadores e muitos outros tipos de artefatos NÃO são candidatos para serialização.

Jeroen van Bergen
fonte
0

Bem, minha resposta é que isso não é uma boa razão. E pelos seus comentários, posso ver que você já aprendeu isso. Outras linguagens tentam serializar tudo o que não pula em uma árvore depois que você conta até 10. Um objeto deve ser serializável por padrão.

Então, o que você basicamente precisa fazer é ler todas as propriedades de sua classe de terceiros. Ou, se essa for uma opção para você: descompilar, colocar a maldita palavra-chave lá e recompilar.

nes1983
fonte
2
A serialização adiciona restrições e problemas potenciais, uma vez que a compatibilidade da estrutura não é garantida. IMHO, é bom que ele esteja desligado por padrão.
Uri
Não tenho certeza do que você entende por "compatibilidade de estrutura".
nes1983
0

Existem algumas coisas em Java que simplesmente não podem ser serializadas porque são específicas do tempo de execução. Coisas como streams, threads, runtime, etc. e até mesmo algumas classes GUI (que estão conectadas ao SO subjacente) não podem ser serializadas.


fonte
0

Embora eu concorde com os pontos apresentados em outras respostas aqui, o verdadeiro problema é com a desserialização: se a definição da classe mudar, então há um risco real de que a desserialização não funcione. Nunca modificar campos existentes é um compromisso muito importante para o autor de uma biblioteca! Manter a compatibilidade da API já é uma tarefa árdua.

CurtainDog
fonte
Isso não está correto. Você precisa ler o capítulo Versioning of Serializable Objects da Object Serialization Specification, que não existiria se o que você afirma aqui fosse verdade. A definição da classe pode mudar dentro de limites bastante amplos antes de se tornar incompatível com serializações anteriores. E certamente não é a resposta à pergunta. O verdadeiro motivo tem a ver com questões de segurança.
Marquês de Lorne,
@EJP, no interesse da veracidade, editei minha resposta para refletir seus pontos. O sentimento permanece, porém, é um grande compromisso que definitivamente deveria ser opt-in ao invés de opt-out
CurtainDog
0

Uma classe que precisa ser persistida em um arquivo ou outra mídia deve implementar a interface Serializable, para que a JVM possa permitir que o objeto de classe seja serializado. Por que a classe Object não é serializada, nenhuma das classes precisa implementar a interface, afinal a JVM serializa a classe apenas quando eu uso ObjectOutputStream, o que significa que o controle ainda está em minhas mãos para permitir que a JVM seja serializada.

A razão pela qual a classe Object não é serializável por padrão é o fato de que a versão da classe é o principal problema. Portanto, cada classe interessada em serialização deve ser marcada explicitamente como serializável e fornecer um número de versão serialVersionUID.

Se serialVersionUID não for fornecido, obteremos resultados inesperados ao desserializar o objeto, é por isso que a JVM lança InvalidClassException se serialVersionUID não corresponder. Portanto, cada classe deve implementar a interface Serializable e fornecer serialVersionUID para garantir que a classe apresentada nas duas extremidades seja idêntica.

Trinesh Andhurthi
fonte