CodeGym /Cursos /JAVA 25 SELF /ObjectOutputStream, ObjectInputStream: trabalhando com fl...

ObjectOutputStream, ObjectInputStream: trabalhando com fluxos

JAVA 25 SELF
Nível 42 , Lição 3
Disponível

1. Introdução

Em Java, a serialização só funciona com objetos que explicitamente permitem isso. Para tanto, a classe deve implementar a interface especial — java.io.Serializable.

import java.io.Serializable;

public class Person implements Serializable {
    // Campos, construtores, métodos
}

Serializable é uma interface marcadora: ela não possui métodos; apenas informa à JVM — “esta classe pode ser serializada, não se preocupe!”. Se você tentar serializar um objeto de uma classe que não implementa Serializable, receberá a exceção NotSerializableException. Mesmo que ao menos um campo (ou um objeto aninhado) não seja serializável — a serialização não funcionará.

ObjectOutputStream e ObjectInputStream

  • ObjectOutputStream — classe que grava objetos em um fluxo (por exemplo, em um arquivo ou pela rede).
  • ObjectInputStream — classe que lê objetos de um fluxo.

Eles funcionam em pares: um serializa o objeto, o outro — desserializa.

Métodos principais

  • writeObject(Object obj) — serializa o objeto e o grava no fluxo.
  • readObject() — lê um objeto do fluxo, desserializa e o retorna.

Importante: ambas as classes funcionam sobre fluxos de entrada e saída comuns (OutputStream e InputStream). Com mais frequência, são usadas com fluxos de arquivo — FileOutputStream e FileInputStream, mas também podem ser aplicadas com fluxos de rede.

2. Exemplo de serialização

Vamos escrever um exemplo simples: serializar e desserializar um objeto da classe Person.

Passo 1. Descrever a classe

import java.io.Serializable;

public class Person implements Serializable {
    private String name;
    private int age;
    // campo transient não será serializado
    private transient String secret;

    public Person(String name, int age, String secret) {
        this.name = name;
        this.age = age;
        this.secret = secret;
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + ", secret='" + secret + "'}";
    }
}

Passo 2. Serializar o objeto para um arquivo

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class SerializeDemo {
    public static void main(String[] args) throws Exception {
        Person person = new Person("Alice", 30, "likes pizza");

        // Criamos um fluxo para gravar no arquivo
        FileOutputStream fileOut = new FileOutputStream("person.bin");
        ObjectOutputStream out = new ObjectOutputStream(fileOut);

        // Salvamos o objeto
        out.writeObject(person);

        // Fechamos os fluxos
        out.close();
        fileOut.close();

        System.out.println("Objeto serializado no arquivo person.bin");
    }
}

Passo 3. Desserializar o objeto do arquivo

import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class DeserializeDemo {
    public static void main(String[] args) throws Exception {
        // Abrimos o fluxo para leitura do arquivo
        FileInputStream fileIn = new FileInputStream("person.bin");
        ObjectInputStream in = new ObjectInputStream(fileIn);

        // Recuperamos o objeto
        Person person = (Person) in.readObject();

        in.close();
        fileIn.close();

        System.out.println("Objeto desserializado: " + person);
    }
}

Saída esperada

Objeto serializado no arquivo person.bin
Objeto desserializado: Person{name='Alice', age=30, secret='null'}

Atenção! O campo transient não é serializado. Após a desserialização, ele será igual a null. Isso é importante para dados temporários ou sensíveis.

3. Restrições e particularidades

Todos os campos devem ser serializáveis

Se a classe tiver campos que não implementam Serializable (ou contêm tais objetos), a serialização terminará com erro. Por exemplo, campos do tipo Thread ou Socket não podem ser tornados serializáveis “simplesmente”.

Campos estáticos e transient

  • Campos estáticos (static) não são serializados: eles pertencem à classe, não a um objeto específico.
  • Campos transient — marcados como transient são explicitamente excluídos da serialização e, após a recuperação, recebem valores padrão (null, 0 etc.).

Exceções

  • A tentativa de serializar um objeto que não implementa Serializable lança NotSerializableException.
  • Ao desserializar, erros podem ocorrer: arquivo não encontrado, incompatibilidade de classes, dados corrompidos etc.

Versões de classes

Se você alterar a estrutura da classe após a serialização (por exemplo, adicionar/remover campos), durante a desserialização pode ocorrer InvalidClassException. Para controle de versão, usa-se o campo especial serialVersionUID (mais detalhes em uma das próximas aulas).

4. Prática: serialização e desserialização de um objeto para arquivo

Suponha que temos a classe Person e queremos salvar uma lista de pessoas em um arquivo e lê-la de volta.

Classe Person (serializável)

import java.io.Serializable;

public class Person implements Serializable {
    private String name;
    private int age;
    private transient String secret; // não será serializado

    public Person(String name, int age, String secret) {
        this.name = name;
        this.age = age;
        this.secret = secret;
    }

    @Override
    public String toString() {
        return name + " (" + age + "), secret: " + secret;
    }
}

Serialização da lista de pessoas

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

public class SerializeListDemo {
    public static void main(String[] args) throws Exception {
        List<Person> people = new ArrayList<>();
        people.add(new Person("Alice", 30, "likes pizza"));
        people.add(new Person("Bob", 25, "hates broccoli"));

        FileOutputStream fileOut = new FileOutputStream("people.bin");
        ObjectOutputStream out = new ObjectOutputStream(fileOut);

        // Salvamos a lista
        out.writeObject(people);

        out.close();
        fileOut.close();

        System.out.println("Lista de pessoas serializada.");
    }
}

Desserialização da lista de pessoas

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.List;

public class DeserializeListDemo {
    public static void main(String[] args) throws Exception {
        FileInputStream fileIn = new FileInputStream("people.bin");
        ObjectInputStream in = new ObjectInputStream(fileIn);

        // Recuperamos a lista
        List<Person> people = (List<Person>) in.readObject();

        in.close();
        fileIn.close();

        for (Person p : people) {
            System.out.println(p);
        }
    }
}

Resultado:

Alice (30), secret: null
Bob (25), secret: null

5. Erros comuns

Erro nº 1: a classe não implementa Serializable. Se você esquecer de adicionar implements Serializable, ao tentar serializar receberá NotSerializableException. Este é o erro mais comum e simples.

Erro nº 2: Campo não serializável. Se o objeto contiver um campo que não é serializável (por exemplo, Thread, Socket ou qualquer outro tipo sem Serializable), a serialização “vai falhar”. Marque tais campos como transient ou torne-os serializáveis.

Erro nº 3: Alteração da estrutura da classe. Se o objeto foi serializado e, depois, a classe for alterada (campos adicionados/removidos), na leitura pode ocorrer InvalidClassException. Especifique serialVersionUID para um controle de versão estável.

Erro nº 4: Tentativa de serializar campos estáticos. Campos com o modificador static não são serializados. Após a desserialização, seus valores serão aqueles definidos na classe por padrão, e não os que existiam no momento da serialização.

Erro nº 5: Fluxos não fechados. Se você não fechar os fluxos após o uso, pode obter arquivo corrompido ou vazamento de recursos. Use try-with-resources ou feche os fluxos explicitamente.

Erro nº 6: Incompatibilidade de classes. Se a classe foi renomeada ou movida para outro pacote, a desserialização não funcionará — é necessário que o nome e o pacote da classe gravada no fluxo coincidam exatamente.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION