CodeGym /Cursos /JAVA 25 SELF /Inicialização de objeto: ordem de inicialização

Inicialização de objeto: ordem de inicialização

JAVA 25 SELF
Nível 14 , Lição 5
Disponível

1. Ordem de inicialização de um objeto em Java: quem vem primeiro e quem vem por último?

Criar um objeto em Java — não é apenas “alocar memória e gravar valores”. É todo um ritual com uma ordem bem definida de etapas. Se imaginarmos o processo de inicialização como o lançamento de um foguete, cada estágio tem o seu lugar exato.

Quando você escreve:

Person vasya = new Person("Vasya", 30);

O Java executa as seguintes etapas:

  1. Aloca memória para o objeto e atribui valores padrão a todos os campos.
  2. Executa as inicializações explícitas dos campos (se você definiu valores diretamente na declaração).
  3. Executa todos os blocos de inicialização não estáticos (comuns) — na ordem em que aparecem na classe.
  4. Executa o corpo do construtor que você invocou com new.

Vamos analisar cada etapa em detalhes.

2. Inicialização de campos

Valores padrão

Quando o objeto está sendo criado (antes de qualquer atribuição explícita), todos os seus campos recebem valores padrão:

Tipo de campo Valor padrão
int, short, byte, long
0
float, double
0.0
boolean
false
char
'\u0000' (caractere nulo)
Tipos de referência (String, outros objetos)
null

Inicialização explícita

Se você define um valor já na declaração do campo, esse valor será definido depois dos valores padrão, mas antes da execução do construtor.

public class Person {
    private String name = "Sem nome";
    private int age = 18;
}

Se você criar o objeto por meio do construtor vazio, esses valores permanecerão. Se usar um construtor com parâmetros, é bem provável que sejam sobrescritos.

3. Blocos de inicialização: para que servem e como funcionam

No Java você pode declarar os chamados blocos de inicialização não estáticos. Eles são executados toda vez que um objeto é criado, imediatamente após a inicialização dos campos, mas antes do construtor.

Sintaxe:

public class Person {
    {
        System.out.println("Executando bloco de inicialização não estático!");
    }
}

Se a classe tiver vários blocos desse tipo, eles são executados na ordem em que aparecem.

Exemplo com vários blocos

public class Person {
    private String name = "Sem nome";

    {
        System.out.println("Bloco 1: name = " + name);
        name = "Enigma";
    }

    {
        System.out.println("Bloco 2: name = " + name);
    }

    public Person() {
        System.out.println("Construtor: name = " + name);
    }
}

Se criarmos um objeto:

Person p = new Person();

A saída será:

Bloco 1: name = Sem nome
Bloco 2: name = Enigma
Construtor: name = Enigma

Para que servem os blocos de inicialização?

Na prática, os blocos de inicialização são usados raramente. Normalmente, tudo que pode ser feito em um bloco também pode ser feito na declaração do campo ou no construtor. Mas, às vezes (por exemplo, quando há vários construtores e parte da lógica de inicialização precisa ser comum a todos), os blocos de inicialização podem ser convenientes.

4. Construtor: o acorde final da inicialização

Depois que todos os campos receberam valores (padrão ou explícitos) e todos os blocos de inicialização foram executados, o construtor é chamado — exatamente aquele que você indicou após new.

No construtor você geralmente define os valores finais dos campos, recebe parâmetros e executa outras inicializações que dependem dos dados de entrada.

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        System.out.println("Construtor: name = " + name + ", age = " + age);
        this.name = name;
        this.age = age;
    }
}

5. Demonstração da ordem completa de inicialização

Vamos escrever uma classe que mostre explicitamente em que ordem a inicialização acontece.

public class Person {
    private String name = "Sem nome";
    private int age = 18;

    {
        System.out.println("Bloco de inicialização: name = " + name + ", age = " + age);
        age = 21;
    }

    public Person() {
        System.out.println("Construtor sem parâmetros: name = " + name + ", age = " + age);
    }

    public Person(String name, int age) {
        System.out.println("Construtor com parâmetros: name = " + name + ", age = " + age);
        this.name = name;
        this.age = age;
    }

    public void printInfo() {
        System.out.println("Person: name = " + name + ", age = " + age);
    }
}

E agora, na nossa classe principal (por exemplo, Main):

public class Main {
    public static void main(String[] args) {
        System.out.println("Criando o objeto p1:");
        Person p1 = new Person();
        p1.printInfo();

        System.out.println("\nCriando o objeto p2:");
        Person p2 = new Person("Petya", 30);
        p2.printInfo();
    }
}

A saída será aproximadamente assim:

Criando o objeto p1:
Bloco de inicialização: name = Sem nome, age = 18
Construtor sem parâmetros: name = Sem nome, age = 21
Person: name = Sem nome, age = 21

Criando o objeto p2:
Bloco de inicialização: name = Sem nome, age = 18
Construtor com parâmetros: name = Sem nome, age = 21
Person: name = Petya, age = 30

Atenção: no construtor com parâmetros, os valores dos campos ainda são os antigos (aqueles após o bloco de inicialização); somente depois do construtor os campos recebem os valores finais.

6. Diagrama da ordem de inicialização

Aqui vai um pequeno diagrama (fluxograma) para visualizar:

flowchart TD
    A[Alocação de memória, valores padrão] --> B[Inicialização explícita dos campos]
    B --> C[Execução dos blocos de inicialização não estáticos]
    C --> D[Execução do construtor]
    D --> E[Objeto pronto para uso]

7. Particularidades e nuances

Campos estáticos e blocos estáticos

Nesta aula falamos apenas de campos e blocos não estáticos (comuns). Campos e blocos estáticos são inicializados uma única vez no carregamento da classe, e não a cada criação de objeto. Falaremos mais sobre eles nos tópicos de encapsulamento.

Quando é que cada coisa é inicializada?

  • Campos — a cada criação de objeto.
  • Blocos de inicialização — a cada criação de objeto.
  • Campos e blocos estáticos — apenas uma vez, no carregamento da classe.

É possível acessar campos nos blocos de inicialização?

Sim, é possível! Mas é importante lembrar que, se o campo for declarado abaixo do bloco, ele já existe; porém, se você acessá-lo antes da inicialização explícita, receberá o valor padrão.

8. Erros comuns na inicialização de objetos

Erro nº 1: Esperar que os campos sejam inicializados antes da sua declaração.
Em Java, a ordem de declaração de campos e blocos de inicialização na classe faz diferença. Se, em um bloco de inicialização, você acessar um campo declarado abaixo, ele já existirá, mas ainda não terá sido inicializado explicitamente — terá o valor padrão.

Erro nº 2: Duplicar a inicialização em blocos e construtores.
Iniciantes costumam repetir a mesma lógica tanto no bloco quanto no construtor. É melhor usar ou o bloco, ou o construtor, ou então chamar um construtor a partir de outro via this(...).

Erro nº 3: Esperar que campos estáticos sejam inicializados a cada criação de objeto.
Campos e blocos estáticos funcionam de forma diferente — são inicializados apenas uma vez, no carregamento da classe.

Erro nº 4: Uso de campos de referência não inicializados.
Se você esquecer de inicializar explicitamente um campo de referência (por exemplo, String name;), ele será igual a null até que você lhe atribua um valor explicitamente em um bloco de inicialização ou no construtor.

1
Pesquisa/teste
Classes e construtores, nível 14, lição 5
Indisponível
Classes e construtores
Classes e construtores
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION