Qual é a diferença entre Serializable
e Externalizable
em Java?
Qual é a diferença entre Serializable
e Externalizable
em Java?
Respostas:
Para adicionar às outras respostas, implementando java.io.Serializable
, você obtém o recurso de serialização "automática" para objetos de sua classe. Não há necessidade de implementar nenhuma outra lógica, apenas funcionará. O tempo de execução do Java usará a reflexão para descobrir como organizar e remover a organização de seus objetos.
Na versão anterior do Java, a reflexão era muito lenta e, portanto, serializar grandes gráficos de objetos (por exemplo, em aplicativos RMI cliente-servidor) era um problema de desempenho. Para lidar com essa situação, java.io.Externalizable
foi fornecida a interface, que é semelhante a java.io.Serializable
mecanismos escritos sob medida para executar as funções de empacotamento e descompactação (você precisa implementar readExternal
ewriteExternal
métodos em sua classe). Isso fornece os meios para contornar o gargalo do desempenho da reflexão.
Nas versões recentes do Java (1.3 em diante, certamente), o desempenho da reflexão é muito melhor do que costumava ser e, portanto, isso é muito menos problemático. Eu suspeito que você seria pressionado para obter um benefício significativo deExternalizable
com uma JVM moderna.
Além disso, o mecanismo de serialização Java embutido não é o único; você pode obter substituições de terceiros, como a JBoss Serialization, que é consideravelmente mais rápida e é uma substituição do padrão.
Uma grande desvantagem Externalizable
é que você deve manter essa lógica - se você adicionar, remover ou alterar um campo em sua classe, precisará alterar seus writeExternal
/ readExternal
métodos para dar conta disso.
Em resumo, Externalizable
é uma relíquia dos Java 1.1 dias. Realmente não há mais necessidade disso.
Externalizable
ajuda bastante .
Externalizable
me convém muito melhor, pois não quero gerar matrizes com espaços vazios ou objetos de espaço reservado, além da interface explícita de que você pode lidar com herança, o que significa que meu sub sincronizado -class pode facilmente adicionar bloqueio à chamada writeExternal()
. Então, o Externalizable ainda é muito relevante, certamente para objetos grandes ou complexos.
A serialização fornece a funcionalidade padrão para armazenar e recriar posteriormente o objeto. Ele usa o formato detalhado para definir o gráfico inteiro dos objetos a serem armazenados, por exemplo, suponha que você tenha uma lista vinculada e codifique como abaixo, a serialização padrão descobrirá todos os objetos que estão vinculados e serializará. Na serialização padrão, o objeto é construído inteiramente a partir de seus bits armazenados, sem chamadas do construtor.
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("/Users/Desktop/files/temp.txt"));
oos.writeObject(linkedListHead); //writing head of linked list
oos.close();
Mas se você deseja serialização restrita ou não deseja que parte do seu objeto seja serializada, use Externalizable. A interface Externalizável estende a interface Serializável e adiciona dois métodos, writeExternal () e readExternal (). Eles são chamados automaticamente durante a serialização ou desserialização. Ao trabalhar com Externalizable, devemos lembrar que o construtor padrão deve ser público; caso contrário, o código gerará uma exceção. Por favor, siga o código abaixo:
public class MyExternalizable implements Externalizable
{
private String userName;
private String passWord;
private Integer roll;
public MyExternalizable()
{
}
public MyExternalizable(String userName, String passWord, Integer roll)
{
this.userName = userName;
this.passWord = passWord;
this.roll = roll;
}
@Override
public void writeExternal(ObjectOutput oo) throws IOException
{
oo.writeObject(userName);
oo.writeObject(roll);
}
@Override
public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException
{
userName = (String)oi.readObject();
roll = (Integer)oi.readObject();
}
public String toString()
{
StringBuilder b = new StringBuilder();
b.append("userName: ");
b.append(userName);
b.append(" passWord: ");
b.append(passWord);
b.append(" roll: ");
b.append(roll);
return b.toString();
}
public static void main(String[] args)
{
try
{
MyExternalizable m = new MyExternalizable("nikki", "student001", 20);
System.out.println(m.toString());
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/Desktop/files/temp1.txt"));
oos.writeObject(m);
oos.close();
System.out.println("***********************************************************************");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/Desktop/files/temp1.txt"));
MyExternalizable mm = (MyExternalizable)ois.readObject();
mm.toString();
System.out.println(mm.toString());
}
catch (ClassNotFoundException ex)
{
Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
}
catch(IOException ex)
{
Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Aqui, se você comentar o construtor padrão, o código será exibido abaixo da exceção:
java.io.InvalidClassException: javaserialization.MyExternalizable;
javaserialization.MyExternalizable; no valid constructor.
Podemos observar que, como a senha é uma informação sensível, não a serializo no método writeExternal (ObjectOutput oo) e não configuro o valor igual em readExternal (ObjectInput oi). Essa é a flexibilidade fornecida pelo Externalizable.
A saída do código acima é conforme abaixo:
userName: nikki passWord: student001 roll: 20
***********************************************************************
userName: nikki passWord: null roll: 20
Podemos observar que não estamos definindo o valor de passWord, portanto é nulo.
O mesmo também pode ser alcançado declarando o campo da senha como transitório.
private transient String passWord;
Espero que ajude. Peço desculpas se cometi algum erro. Obrigado.
Principais diferenças entre Serializable
eExternalizable
Serializable
é a interface do marcador sem nenhum método. Externalizable
A interface contém dois métodos: writeExternal()
e readExternal()
.Serializable
interface. O processo de serialização definido pelo programador será ativado nas classes que implementam a Externalizable
interface.Externalizable
interface. Você pode suportar versões diferentes do seu objeto. Se você implementar Externalizable
, é sua responsabilidade serializar a super
classeSerializable
usa reflexão para construir objeto e não requer nenhum construtor arg. Mas Externalizable
exige um construtor público sem argumentos.Consulte o blog por Hitesh Garg
para mais detalhes.
A serialização usa certos comportamentos padrão para armazenar e depois recriar o objeto. Você pode especificar em que ordem ou como lidar com referências e estruturas de dados complexas, mas eventualmente se resume ao uso do comportamento padrão para cada campo de dados primitivo.
A externalização é usada nos casos raros em que você realmente deseja armazenar e reconstruir seu objeto de uma maneira completamente diferente e sem usar os mecanismos de serialização padrão para os campos de dados. Por exemplo, imagine que você tivesse seu próprio esquema de codificação e compactação.
A serialização de objetos usa as interfaces serializáveis e externalizáveis. Um objeto Java é apenas serializável. se uma classe ou qualquer uma de suas superclasses implementa a interface java.io.Serializable ou sua subinterface, java.io.Externalizable. A maioria da classe java é serializável .
NotSerializableException
: packageName.ClassName
«Para participar de um objeto de classe no processo de serialização, a classe deve implementar a interface serializável ou externalizável.A serialização de objetos produz um fluxo com informações sobre as classes Java para os objetos que estão sendo salvos. Para objetos serializáveis, informações suficientes são mantidas para restaurar esses objetos, mesmo que uma versão diferente (mas compatível) da implementação da classe esteja presente. A interface serializável é definida para identificar as classes que implementam o protocolo serializável:
package java.io;
public interface Serializable {};
InvalidClassException
«No processo de desserialização, se o valor serialVersionUID da classe local for diferente da classe do remetente correspondente. então o resultado está em conflito como
java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
Para objetos Externalizáveis, apenas a identidade da classe do objeto é salva pelo contêiner; a classe deve salvar e restaurar o conteúdo. A interface Externalizável é definida da seguinte maneira:
package java.io;
public interface Externalizable extends Serializable
{
public void writeExternal(ObjectOutput out)
throws IOException;
public void readExternal(ObjectInput in)
throws IOException, java.lang.ClassNotFoundException;
}
OptionalDataException
«Os campos DEVEM ESTAR NA MESMA ORDEM E TIPO, como escrevemos. Se houver alguma incompatibilidade de tipo no fluxo, ele lançará OptionalDataException.
@Override public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt( id );
out.writeUTF( role );
out.writeObject(address);
}
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.address = (Address) in.readObject();
this.role = in.readUTF();
}
Os campos de instância da classe que gravaram (expostos) para ObjectOutput
serem serializados.
Exemplo « implementa Serializable
class Role {
String role;
}
class User extends Role implements Serializable {
private static final long serialVersionUID = 5081877L;
Integer id;
Address address;
public User() {
System.out.println("Default Constructor get executed.");
}
public User( String role ) {
this.role = role;
System.out.println("Parametarised Constructor.");
}
}
class Address implements Serializable {
private static final long serialVersionUID = 5081877L;
String country;
}
Exemplo « implementa Externalizável
class User extends Role implements Externalizable {
Integer id;
Address address;
// mandatory public no-arg constructor
public User() {
System.out.println("Default Constructor get executed.");
}
public User( String role ) {
this.role = role;
System.out.println("Parametarised Constructor.");
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt( id );
out.writeUTF( role );
out.writeObject(address);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.address = (Address) in.readObject();
this.role = in.readUTF();
}
}
Exemplo
public class CustomClass_Serialization {
static String serFilename = "D:/serializable_CustomClass.ser";
public static void main(String[] args) throws IOException {
Address add = new Address();
add.country = "IND";
User obj = new User("SE");
obj.id = 7;
obj.address = add;
// Serialization
objects_serialize(obj, serFilename);
objects_deserialize(obj, serFilename);
// Externalization
objects_WriteRead_External(obj, serFilename);
}
public static void objects_serialize( User obj, String serFilename ) throws IOException{
FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
// java.io.NotSerializableException: com.github.objects.Address
objectOut.writeObject( obj );
objectOut.flush();
objectOut.close();
fos.close();
System.out.println("Data Stored in to a file");
}
public static void objects_deserialize( User obj, String serFilename ) throws IOException{
try {
FileInputStream fis = new FileInputStream( new File( serFilename ) );
ObjectInputStream ois = new ObjectInputStream( fis );
Object readObject;
readObject = ois.readObject();
String calssName = readObject.getClass().getName();
System.out.println("Restoring Class Name : "+ calssName); // InvalidClassException
User user = (User) readObject;
System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);
Address add = (Address) user.address;
System.out.println("Inner Obj : "+ add.country );
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void objects_WriteRead_External( User obj, String serFilename ) throws IOException {
FileOutputStream fos = new FileOutputStream(new File( serFilename ));
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
obj.writeExternal( objectOut );
objectOut.flush();
fos.close();
System.out.println("Data Stored in to a file");
try {
// create a new instance and read the assign the contents from stream.
User user = new User();
FileInputStream fis = new FileInputStream(new File( serFilename ));
ObjectInputStream ois = new ObjectInputStream( fis );
user.readExternal(ois);
System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);
Address add = (Address) user.address;
System.out.println("Inner Obj : "+ add.country );
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
@Vejo
A interface Externalizável não foi realmente fornecida para otimizar o desempenho do processo de serialização! mas para fornecer meios de implementar seu próprio processamento personalizado e oferecer controle completo sobre o formato e o conteúdo do fluxo de um objeto e seus supertipos!
Exemplos disso é a implementação do sistema de comunicação remota AMF (ActionScript Message Format) para transferir objetos de script de ação nativo pela rede.
https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html
A serialização padrão é um tanto detalhada e assume o cenário de uso mais amplo possível do objeto serializado e, portanto, o formato padrão (Serializable) anota o fluxo resultante com informações sobre a classe do objeto serializado.
A externalização fornece ao produtor do fluxo de objetos controle completo sobre os metadados precisos da classe (se houver) além da identificação mínima exigida da classe (por exemplo, seu nome). Isso é claramente desejável em determinadas situações, como ambientes fechados, onde o produtor do fluxo de objetos e seu consumidor (que reifica o objeto do fluxo) são correspondidos, e os metadados adicionais sobre a classe não servem para nada e prejudicam o desempenho.
Além disso (como Uri salienta), a externalização também fornece controle completo sobre a codificação dos dados no fluxo correspondente aos tipos Java. Para um exemplo (artificial), você pode querer registrar boolean true como 'Y' e false como 'N'. A externalização permite que você faça isso.
Ao considerar opções para melhorar o desempenho, não se esqueça da serialização personalizada. Você pode deixar o Java fazer o que faz bem, ou pelo menos ser bom o suficiente, de graça , e fornecer suporte personalizado para o que faz mal. Geralmente, esse código é muito menor que o suporte total a Externalizável.
Existem tantas diferenças entre Serializable e Externalizable, mas quando comparamos a diferença entre Serializable personalizado (writeObject (substituído por readObject () e readObject ()) e Externalizable, descobrimos que a implementação personalizada está fortemente ligada à classe ObjectOutputStream, onde, como no caso Externalizable, nós mesmos forneça uma implementação de ObjectOutput que pode ser a classe ObjectOutputStream ou pode ser outra, como org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream
No caso de interface Externalizável
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(key);
out.writeUTF(value);
out.writeObject(emp);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.key = in.readUTF();
this.value = in.readUTF();
this.emp = (Employee) in.readObject();
}
**In case of Serializable interface**
/*
We can comment below two method and use default serialization process as well
Sequence of class attributes in read and write methods MUST BE same.
// below will not work it will not work .
// Exception = java.io.StreamCorruptedException: invalid type code: 00\
private void writeObject(java.io.ObjectOutput stream)
*/
private void writeObject(java.io.ObjectOutputStream Outstream)
throws IOException {
System.out.println("from writeObject()");
/* We can define custom validation or business rules inside read/write methods.
This way our validation methods will be automatically
called by JVM, immediately after default serialization
and deserialization process
happens.
checkTestInfo();
*/
stream.writeUTF(name);
stream.writeInt(age);
stream.writeObject(salary);
stream.writeObject(address);
}
private void readObject(java.io.ObjectInputStream Instream)
throws IOException, ClassNotFoundException {
System.out.println("from readObject()");
name = (String) stream.readUTF();
age = stream.readInt();
salary = (BigDecimal) stream.readObject();
address = (Address) stream.readObject();
// validateTestInfo();
}
Eu adicionei um código de exemplo para explicar melhor. verifique / in / out objeto caso Externalizable. Eles não estão vinculados a nenhuma implementação diretamente.
Onde Outstream / Instream estão fortemente vinculados a classes. Podemos estender ObjectOutputStream / ObjectInputStream, mas será um pouco difícil de usar.
Basicamente, Serializable
é uma interface de marcador que implica que uma classe é segura para serialização e a JVM determina como ela é serializada. Externalizable
contém 2 métodos readExternal
e writeExternal
. Externalizable
permite que o implementador decida como um objeto é serializado, onde como Serializable
serializa objetos da maneira padrão.
Algumas diferenças:
Para serialização, não há necessidade do construtor padrão dessa classe, porque Object porque a JVM constrói o mesmo com a ajuda da API de reflexão. No caso de externalização, o contratador sem argumento é necessário, porque o controle está na mão do programmar e, posteriormente, atribui os dados desserializados ao objeto por meio de setters.
Na serialização, se o usuário desejar pular certas propriedades a serem serializadas, precisará marcar essas propriedades como transitórias, e vice-versa não será necessário para Externalização.
Quando o suporte à compatibilidade com versões anteriores é esperado para qualquer classe, é recomendável usar o Externalizable. A serialização suporta a persistência de defaultObject e, se a estrutura do objeto estiver quebrada, causará problemas durante a desserialização.