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 interface java.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 interface java.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 tipo java.io.NotSerializableException será lançada.

2. Métodos de serialização

Execute os passos listados a seguir para criar um objeto serializado:

Listagem 1. Serializando um objeto
//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);
Listagem 2. Recuperando um objeto serializado
//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. 

imagem de exemplo

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.

Listagem 3. RadioList, classe a ser serializada.
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 List radioButtonList = 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.

Listagem 4. Método para serializar
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.

Listagem 5. Método para recuperar o objeto serializado
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.

Listagem 6. Interface Gráfica.
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 ArrayList radioButtons;

    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.

Download via Github

Ballem

Marcio Ballem é bacharel em Sistemas de Informação pelo Centro Universitário Franciscano em Santa Maria/RS. Tem experiência com desenvolvimento Delphi e Java em projetos para gestão pública e acadêmica. Possui certificação em Java, OCJP 6.

Você pode gostar...