Serialização em Java
O processo de serialização resume-se em salvar e recuperar o estado de um objeto. Imagine que você está desenvolvendo um jogo. Neste jogo o jogador terá a opção de salvar e recomeçar o jogo de onde parou. Com a serialização é possível fazer isso salvando o estado do jogo em um arquivo serializado e futuramente ler este arquivo e reiniciar o jogo daquele ponto.
Para ficar mais simples ainda a explicação, imagine que o jogo se desenvolve todo na classe Game. Esta classe contém inúmeros atributos e conforme o jogo se desenrola os valores destes atributos estarão se modificando o tempo todo. Assim, o que será salvo em um arquivo é o estado atual do objeto da classe Game naquele exato momento que o jogador clicar em salvar o jogo.
1. O mais importante à saber sobre serialização
-
Um objeto só poderá ser serializado se for do tipo
java.io.Serializable
. Para isso, basta implementar a interfacejava.io.Serializable
na classe que será serializada. Essa interface não possui nenhum método, é apenas uma indicação para a JVM saber que este objeto pode ser serializado; - Quando o objeto é serializado, todas as variáveis de instância referentes a classe deste objeto serão serializadas;
-
Subclasses automaticamente são do tipo
Serializable
caso sua superclasse tenha implementado a interfacejava.io.Serializable
; - Variáveis estáticas não são serializadas, já que não fazem parte da instância da classe. Sendo assim, valores de variáveis estáticas não podem ser salvos e nem recuperados através de serialização;
-
Caso tente serializar um objeto que não for do tipo
Serializable
, uma exceção do tipojava.io.NotSerializableException
será lançada.
2. Métodos de serialização
Execute os passos listados a seguir para criar um objeto serializado:
//crie um objeto do tipo FileOutputStream java.io.FileOutputStream fos = new java.io.FileOutputStream(new File("file name")); //crie um objeto do tipo ObjectOutputStream java.io.ObjectOutputStream os = new java.io.ObjectOutputStream(fos); //passe como parametro ao método writeObject() o objeto a ser serializado os.writeObject(your_object);
//crie um objeto do tipo FileInputStream java.io.FileInputStream fis = new java.io.FileInputStream(new File("file name")); //crie um objeto do tipo ObjectInputStream java.io.ObjectInputStream is = new java.io.ObjectInputStream(fis); //através do método readObject() recupere seu objeto. //faça um cast para o tipo esperado. your_object = (YourObjetc) is.readObject();
Vamos agora criar um exemplo de serialização. Para isso, veja na figura abaixo um interface gráfica com vários JRadionButtons
. Alguns deles estão selecionados e outros não. O objetivo será salvar o estado deste objeto para depois recuperá-lo.
A classe que será serializada é muito simples, como você pode visualizar na Listagem 3. Note que a classe RadioList
implementa a interface java.io.Serializable
. Como variável de instancia temos o java.util.List
do tipo javax.swing.JRadioButton
.
package com.mballem.tutorial; import javax.swing.*; import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class RadioList implements Serializable { private ListradioButtonList = new ArrayList (); public List getRadioButtonList() { return radioButtonList; } public void setRadioButtonList(List radioButtonList) { this.radioButtonList = radioButtonList; } }
Para salva o arquivo vamos criar uma classe chamada SerializeService
. Na Listagem 4 temos o método toSerialize()
que irá salvar em um arquivo o objeto serializado. Como parâmetro será adicionado um objeto do tipo RadioList
, o qual queremos salvar no arquivo. O objeto JFileChooser
será usado para abrir uma janela e informar o nome do arquivo e o local onde você vai salva-lo. Os objetos FileOutputStream
e ObjectOutputStream
já foram explicados anteriormente. Desta forma, se nenhum erro ocorrer, será salvo um arquivo serializado com o estado atual do objeto radioList
.
public class SerializeService { public void toSerialize(RadioList radioList) { try { JFileChooser fileChooser = new JFileChooser(); fileChooser.showSaveDialog(null); File file = new File(fileChooser.getSelectedFile().getAbsolutePath()); FileOutputStream fileStream = new FileOutputStream(file); ObjectOutputStream os = new ObjectOutputStream(fileStream); os.writeObject(radioList); } catch (FileNotFoundException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } } }
Para recuperar o estado deste objeto, basta criar um método que lê o arquivo salvo anteriormente. Veja na Listagem 5 o método toDeserialize()
. Neste método temos como retorno um objeto do tipo RadioList
. Usamos o JFileChooser
para selecionar o arquivo a ser recuperado e o restante do código já foi anteriormente explicado.
public class SerializeService { public void toSerialize(RadioList radioList) { //código omitido } public RadioList toDeserialize() { RadioList radioList = null; try { JFileChooser fileChooser = new JFileChooser(); fileChooser.showOpenDialog(null); File file = new File(fileChooser.getSelectedFile().getAbsolutePath()); FileInputStream fis = new FileInputStream(file); ObjectInputStream is = new ObjectInputStream(fis); radioList = (RadioList) is.readObject(); } catch (FileNotFoundException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } catch (ClassNotFoundException e1) { e1.printStackTrace(); } return radioList; } }
Na Listagem 6 temos o código que gera a interface gráfica. Na linha 13 foi adicionada a variável de instancia radioButtons
. Na linha 44 temos um laço de repetição que irá criar 204 JRadioButtons
e adiciona-los a lista radioButtons
. Todos os JRadioButtons
são inicialmente configurados com o valor false
, ou seja, nenhum deles estará selecionado.
package com.mballem.tutorial; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; public class RadioPanel { private JPanel panel; private JFrame frame; private ArrayListradioButtons; public void buildGUI() { frame = new JFrame("Serializable"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); BorderLayout layout = new BorderLayout(); JPanel background = new JPanel(layout); background.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); radioButtons = new ArrayList (); Box buttonBox = new Box(BoxLayout.Y_AXIS); JButton btnSave = new JButton("Save"); btnSave.addActionListener(new MySaveListener()); buttonBox.add(btnSave); JButton btnLoad = new JButton("Load"); btnLoad.addActionListener(new MyLoadListener()); buttonBox.add(btnLoad); background.add(BorderLayout.EAST, buttonBox); frame.getContentPane().add(background); GridLayout grid = new GridLayout(12, 12); grid.setVgap(1); grid.setHgap(2); panel = new JPanel(grid); background.add(BorderLayout.CENTER, panel); for (int i = 0; i < 204; i++) { JRadioButton rb = new JRadioButton(); rb.setSelected(false); radioButtons.add(rb); panel.add(rb); } frame.setBounds(50, 50, 300, 300); frame.pack(); frame.setVisible(true); } /** * Listener button save */ class MySaveListener implements ActionListener { public void actionPerformed(ActionEvent e) { RadioList radioList = new RadioList(); radioList.setRadioButtonList(radioButtons); new SerializeService().toSerialize(radioList); } } /** * Listener button load */ class MyLoadListener implements ActionListener { public void actionPerformed(ActionEvent e) { RadioList radioList = new SerializeService().toDeserialize(); for (int i = 0; i < radioList.getRadioButtonList().size(); i++) { JRadioButton radioButton = radioButtons.get(i); radioButton.setSelected( radioList.getRadioButtonList().get(i).isSelected() ); } } } public static void main(String[] args) { new RadioPanel().buildGUI(); } }
Nesta classe temos ainda dois ouvintes, um para o botão Save
e outro para o botão Load
. Quando o botão Save
for pressionado, o ouvinte MySaveListener
será chamado. A variável radioButtons
será atribuída a um objeto RadioList
e então através de uma instancia da classe SerializeService
, vamos invocar o método toSerialize()
passando como parâmetro o objeto RadioList
e assim, salva-lo em um arquivo.
Para recuperar este estado salvo, pressione o botão Load
e o ouvinte MyLoadListener
será invocado. Recuperamos o conteúdo do arquivo através do método toDeserialize()
da classe SerializeService
. Como retorno teremos um objeto RadioList
. Faremos um for()
neste objeto na lista da classe RadioList
para capturar cada um dos JRadioButton
existente nesta lista. Os JRadioButtons
da interface gráfica serão então recriados com o estado de cada um dos JRadioButtons
salvos no arquivo. Assim, teremos o estado salvo recuperado.
Saiba mais
- Use a Cabeça! Java – Kathy Sierra & Bert Bates.