O que exatamente significa para uma classe estar Serializable
em Java? Ou, em geral, para esse assunto ...
O que exatamente significa para uma classe estar Serializable
em Java? Ou, em geral, para esse assunto ...
Respostas:
A serialização está persistindo um objeto da memória para uma sequência de bits, por exemplo, para salvar no disco. A desserialização é o oposto - ler dados do disco para hidratar / criar um objeto.
No contexto da sua pergunta, é uma interface que, se implementada em uma classe, essa classe pode ser serializada e desserializada automaticamente por diferentes serializadores.
Embora a maioria dos usuários já tenha dado a resposta, gostaria de adicionar um exemplo para aqueles que precisam, a fim de explicar a idéia:
Digamos que você tenha uma pessoa da classe como a seguinte:
public class Person implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
public String firstName;
public String lastName;
public int age;
public String address;
public void play() {
System.out.println(String.format(
"If I win, send me the trophy to this address: %s", address));
}
@Override
public String toString() {
return String.format(".....Person......\nFirst Name = %s\nLast Name = %s", firstName, lastName);
}
}
e então você cria um objeto como este:
Person william = new Person();
william.firstName = "William";
william.lastName = "Kinaan";
william.age = 26;
william.address = "Lisbon, Portugal";
Você pode serializar esse objeto para vários fluxos. Farei isso em dois fluxos:
Serialização para saída padrão:
public static void serializeToStandardOutput(Person person)
throws IOException {
OutputStream outStream = System.out;
ObjectOutputStream stdObjectOut = new ObjectOutputStream(outStream);
stdObjectOut.writeObject(person);
stdObjectOut.close();
outStream.close();
}
Serialização para um arquivo:
public static void serializeToFile(Person person) throws IOException {
OutputStream outStream = new FileOutputStream("person.ser");
ObjectOutputStream fileObjectOut = new ObjectOutputStream(outStream);
fileObjectOut.writeObject(person);
fileObjectOut.close();
outStream.close();
}
Então:
Desserializar do arquivo:
public static void deserializeFromFile() throws IOException,
ClassNotFoundException {
InputStream inStream = new FileInputStream("person.ser");
ObjectInputStream fileObjectIn = new ObjectInputStream(inStream);
Person person = (Person) fileObjectIn.readObject();
System.out.println(person);
fileObjectIn.close();
inStream.close();
}
Isso significa que as instâncias da classe podem ser transformadas em um fluxo de bytes (por exemplo, para serem salvas em um arquivo) e depois convertidas novamente em classes novamente. Esse recarregamento pode ocorrer em uma instância diferente do programa ou mesmo em uma máquina diferente. A serialização (em qualquer idioma) envolve todos os tipos de problemas, especialmente quando você tem referências a outros objetos dentro do serializável.
Aqui está uma explicação detalhada da serialização : (meu próprio blog)
Serialização:
Serialização é o processo de serializar o estado de um objeto que é representado e armazenado na forma de uma sequência de bytes. Isso pode ser armazenado em um arquivo. O processo para ler o estado do objeto no arquivo e restaurá-lo é chamado desserialização.
Qual é a necessidade de serialização?
Na arquitetura moderna, sempre há a necessidade de armazenar o estado do objeto e depois recuperá-lo. Por exemplo, no Hibernate, para armazenar um objeto, devemos tornar a classe Serializable. O que ele faz é que, uma vez que o estado do objeto é salvo na forma de bytes, ele pode ser transferido para outro sistema que pode ler o estado e recuperar a classe. O estado do objeto pode vir de um banco de dados ou de uma jvm diferente ou de um componente separado. Com a ajuda da serialização, podemos recuperar o estado do objeto.
Código Exemplo e explicação:
Primeiro, vamos dar uma olhada na classe Item:
public class Item implements Serializable{
/**
* This is the Serializable class
*/
private static final long serialVersionUID = 475918891428093041L;
private Long itemId;
private String itemName;
private transient Double itemCostPrice;
public Item(Long itemId, String itemName, Double itemCostPrice) {
super();
this.itemId = itemId;
this.itemName = itemName;
this.itemCostPrice = itemCostPrice;
}
public Long getItemId() {
return itemId;
}
@Override
public String toString() {
return "Item [itemId=" + itemId + ", itemName=" + itemName + ", itemCostPrice=" + itemCostPrice + "]";
}
public void setItemId(Long itemId) {
this.itemId = itemId;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public Double getItemCostPrice() {
return itemCostPrice;
}
public void setItemCostPrice(Double itemCostPrice) {
this.itemCostPrice = itemCostPrice;
}
}
No código acima, pode ser visto que a classe Item implementa Serializable .
Essa é a interface que permite que uma classe seja serializável.
Agora podemos ver que uma variável chamada serialVersionUID é inicializada na variável Long. Esse número é calculado pelo compilador com base no estado da classe e nos atributos da classe. Este é o número que ajudará a jvm a identificar o estado de um objeto ao ler o estado do objeto no arquivo.
Para isso, podemos dar uma olhada na documentação oficial da Oracle:
O tempo de execução de serialização associa a cada classe serializável um número de versão, chamado serialVersionUID, usado durante a desserialização para verificar se o remetente e o destinatário de um objeto serializado carregaram classes para esse objeto que são compatíveis com a serialização. Se o receptor carregou uma classe para o objeto que possui um serialVersionUID diferente daquele da classe do remetente correspondente, a desserialização resultará em uma InvalidClassException. Uma classe serializável pode declarar seu próprio serialVersionUID explicitamente declarando um campo chamado "serialVersionUID" que deve ser estático, final e do tipo long: ANY-ACCESS-MODIFIER estático final long serial serialVersionUID = 42L; Se uma classe serializável não declarar explicitamente um serialVersionUID, o tempo de execução da serialização calculará um valor serialVersionUID padrão para essa classe com base em vários aspectos da classe, conforme descrito na Especificação de serialização de objetos Java (TM). No entanto, é altamente recomendável que todas as classes serializáveis declarem explicitamente os valores serialVersionUID, pois a computação serialVersionUID padrão é altamente sensível aos detalhes da classe que podem variar dependendo das implementações do compilador e, portanto, resultar em InvalidClassExceptions inesperadas durante a desserialização. Portanto, para garantir um valor consistente serialVersionUID em diferentes implementações do compilador java, uma classe serializável deve declarar um valor explícito serialVersionUID. Também é altamente recomendável que declarações explícitas serialVersionUID usem o modificador privado sempre que possível,
Se você notou que existe outra palavra-chave que é transitória .
Se um campo não for serializável, ele deve ser marcado como transitório. Aqui, marcamos o itemCostPrice como transitório e não queremos que ele seja gravado em um arquivo
Agora vamos dar uma olhada em como escrever o estado de um objeto no arquivo e depois ler a partir daí.
public class SerializationExample {
public static void main(String[] args){
serialize();
deserialize();
}
public static void serialize(){
Item item = new Item(1L,"Pen", 12.55);
System.out.println("Before Serialization" + item);
FileOutputStream fileOut;
try {
fileOut = new FileOutputStream("/tmp/item.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(item);
out.close();
fileOut.close();
System.out.println("Serialized data is saved in /tmp/item.ser");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void deserialize(){
Item item;
try {
FileInputStream fileIn = new FileInputStream("/tmp/item.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
item = (Item) in.readObject();
System.out.println("Serialized data is read from /tmp/item.ser");
System.out.println("After Deserialization" + item);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
No exemplo acima, podemos ver um exemplo de serialização e desserialização de um objeto.
Para isso, usamos duas classes. Para serializar o objeto, usamos ObjectOutputStream. Nós usamos o método writeObject para gravar o objeto no arquivo.
Para desserializar, usamos ObjectInputStream que lê o objeto no arquivo. Ele usa readObject para ler os dados do objeto no arquivo.
A saída do código acima seria como:
Before SerializationItem [itemId=1, itemName=Pen, itemCostPrice=12.55]
Serialized data is saved in /tmp/item.ser
After DeserializationItem [itemId=1, itemName=Pen, itemCostPrice=null]
Observe que itemCostPrice do objeto desserializado é nulo, pois não foi gravado.
A serialização envolve salvar o estado atual de um objeto em um fluxo e restaurar um objeto equivalente desse fluxo. O fluxo funciona como um contêiner para o objeto
Serializable é chamado como uma interface, mas é mais como um sinalizador para o subsistema Serialization, em tempo de execução. Diz que este objeto pode ser salvo. Todas as variáveis de instância de objetos, com exceção de nenhum objeto serializável e aquelas marcadas como voláteis, serão salvas.
Imagine que seu aplicativo possa alterar a cor como uma opção, sem manter essa configuração externa, você precisará alterar a cor toda vez que a executar.
Serialização é uma técnica para armazenar ou gravar objetos e dados em arquivos. Usando ObjectOutputStream
e FileOutputStream
classes. Essas classes têm seus métodos específicos para persistir os objetos. gostarwriteObject();
para uma explicação clara com figuras. Veja aqui para mais informações
Apresentar de outra perspectiva. A serialização é um tipo de interface chamada 'interface do marcador'. Uma interface de marcador é uma interface que não contém declarações de método, mas apenas designa (ou "marca") uma classe que implementa a interface como tendo alguma propriedade. Se você entender o polimorfismo, isso fará muito sentido. No caso da interface do marcador Serializable, o método ObjectOutputStream.write (Object) falhará se o argumento não implementar a interface. Este é um erro potencial em java, poderia ter sido ObjectOutputStream.write (Serializable)
Altamente recomendado: Leia o item 37 do Effective Java de Joshua Bloch para saber mais.
Serialização: Gravando o estado do objeto em um arquivo / rede ou em qualquer outro lugar. (Formulário médio suportado por objeto Java para formulário suportado por arquivo ou formulário suportado por rede)
Desserialização: Leitura do estado do objeto em Arquivo / Rede ou em qualquer outro lugar. (Formulário médio suportado por arquivo / rede para o formulário suportado por objeto Java)
Apenas para adicionar às outras respostas e com relação à generalidade. A serialização às vezes é conhecida como arquivamento, por exemplo, em Objective-C.
Serializable
:Serializability of a class is enabled by the class implementing the java.io.Serializable interface. Classes that do not implement this interface will not have any of their state serialized or deserialized. All subtypes of a serializable class are themselves serializable. The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.