W3docs

Construtores Java

Use construtores para inicializar objetos Java — padrão, parametrizado e sobrecarregado, mais encadeamento de construtores.

Um construtor é um método especial que é executado uma vez quando um objeto é criado. Seu papel é levar a nova instância de "todos os campos com seus valores padrão" para "pronto para uso." Até agora você vinha definindo campos um por um após new Dog(); um construtor permite agrupar esse trabalho na chamada new.

Anatomia de um construtor

Um construtor parece um método, com três diferenças: ele tem o mesmo nome da classe, não tem tipo de retorno (nem mesmo void), e é chamado apenas por new:

public class Point {
  int x, y;

  public Point(int x, int y) {       // constructor
    this.x = x;
    this.y = y;
  }
}

Point p = new Point(3, 4);           // runs the constructor

A lista de argumentos vai dentro dos () após o nome da classe na expressão new. Java combina essa lista de argumentos com um construtor da classe, assim como combina uma chamada de método com um método.

O construtor padrão

Se você não declarar nenhum construtor, Java fornece à classe um construtor padrão — um construtor sem argumentos que não faz nada:

public class Empty { }    // compiler generates a no-arg constructor

Empty e = new Empty();    // works

É assim que new Dog() funcionava nos exemplos anteriores, mesmo sem termos escrito public Dog() { ... }. No momento em que você declara qualquer construtor próprio, o construtor padrão gratuito desaparece:

public class Point {
  int x, y;
  public Point(int x, int y) { this.x = x; this.y = y; }
}

Point p = new Point();    // ERROR — no no-arg constructor exists

Se você quiser os dois, declare os dois — veja sobrecarga abaixo.

Por que usar um construtor?

Duas razões.

1. Campos obrigatórios. Um construtor permite tornar alguns campos não opcionais. Com campo público e atribuição posterior, nada impede um chamador de criar uma Person sem name. Com um construtor Person(String name), isso é impossível.

2. Invariantes. Um construtor pode validar seus argumentos antes que o objeto exista em forma utilizável. Se um Circle exige um raio positivo, o construtor pode lançar uma exceção para um valor negativo — o objeto com defeito nunca é criado.

public class Circle {
  double radius;
  public Circle(double radius) {
    if (radius <= 0) throw new IllegalArgumentException("radius must be > 0");
    this.radius = radius;
  }
}

O chamador agora não pode obter um Circle com raio não positivo.

Construtores sobrecarregados

Uma classe pode ter vários construtores com listas de parâmetros diferentes, exatamente como métodos sobrecarregados:

public class Rectangle {
  double width, height;

  public Rectangle()                      { this(1, 1); }
  public Rectangle(double side)           { this(side, side); }    // a square
  public Rectangle(double w, double h)    { this.width = w; this.height = h; }
}

Agora estes três compilam:

Rectangle a = new Rectangle();          // 1 x 1
Rectangle b = new Rectangle(5);         // 5 x 5
Rectangle c = new Rectangle(3, 4);      // 3 x 4

Construtores de cópia

Uma sobrecarga comum é um construtor de cópia — um que recebe outra instância da mesma classe e constrói uma cópia independente. Java não tem construtor de cópia embutido (ao contrário do C++), então você escreve o seu quando precisar:

public class Point {
  int x, y;
  public Point(int x, int y) { this.x = x; this.y = y; }
  public Point(Point other)  { this(other.x, other.y); }   // copy constructor
}

Point a = new Point(3, 4);
Point b = new Point(a);    // a separate Point with the same values

Como b é um novo objeto, alterar b.x depois não afeta a. Para classes cujos campos são objetos mutáveis, copie também os campos (uma cópia profunda) se quiser que a cópia seja totalmente independente.

this(...) — encadeamento de construtores

Dentro de um construtor, this(args) chama outro construtor da mesma classe. É assim que o exemplo Rectangle acima evitou duplicar o código de atribuição de campos: os dois construtores de conveniência delegam para o completo.

Duas regras:

  • this(...) deve ser a primeira instrução no corpo do construtor.
  • Um construtor pode encadear para um outro construtor.
public Rectangle()           { this(1, 1); }      // ok
public Rectangle(double s)   { System.out.println("hi"); this(s, s); }   // ERROR

A razão para a regra de "primeira instrução" é que a JVM precisa inicializar o objeto completamente apenas uma vez antes de qualquer outro código ser executado.

super(...) — chamando o pai

Quando uma classe estende outra, cada construtor ou chama explicitamente um construtor pai com super(args), ou chama implicitamente o construtor sem argumentos do pai. Cobriremos isso completamente nos capítulos de herança e palavra-chave super; por ora, saiba apenas que super(...) existe e tem a mesma regra de primeira instrução que this(...).

Construtores não podem retornar um valor

Um construtor não tem tipo de retorno — nem mesmo void. Se você escrever um:

public void Point(int x, int y) { ... }    // not a constructor!

…é um método comum que por acaso se chama Point. O compilador não irá avisá-lo; new Point(3, 4) então falhará ao compilar porque o verdadeiro construtor que está procurando não existe. Este é um erro de digitação surpreendentemente comum.

Ordem de inicialização

Para uma única classe, a ordem é:

  1. Valores padrão dos campos são atribuídos (ex.: campos int tornam-se 0).
  2. Inicializadores de campo inline (int count = 5;) e quaisquer blocos inicializadores de instância são executados na ordem em que aparecem.
  3. O corpo do construtor é executado.
public class Demo {
  int a = compute("a-init", 1);
  int b;

  { b = compute("b-block", 2); }    // instance initializer

  public Demo() {
    System.out.println("constructor; a=" + a + ", b=" + b);
  }

  static int compute(String label, int v) {
    System.out.println(label);
    return v;
  }
}

new Demo() imprime a-init, b-block, depois constructor; a=1, b=2.

Na prática, quase toda inicialização pertence ao corpo do construtor. Blocos inicializadores de instância são raros no código real; existem principalmente para situações como classes anônimas (cobertas mais adiante).

Um exemplo prático

java— editable, runs on the server

O que vem a seguir

Dentro dos construtores você já viu this.field = field para diferenciar um parâmetro de um campo. O capítulo sobre a palavra-chave this explica o que é this e os poucos lugares onde você precisa escrevê-lo explicitamente.

Prática

Prática
Uma classe declara apenas um construtor, public Point(int x, int y). Qual chamada falha?
Uma classe declara apenas um construtor, public Point(int x, int y). Qual chamada falha?
Was this page helpful?