1. Sintaxe da sobrecarga de construtores
Na prática, é raro que todos os objetos sejam criados da mesma maneira. Imagine a classe Person (Pessoa). Às vezes precisamos criar uma pessoa sabendo apenas o nome. Às vezes — nome e idade. E às vezes — não sabemos nada; deixe que tudo fique como padrão. Seria estranho obrigar o usuário da classe a sempre informar todos os parâmetros, mesmo quando ele não precisa deles.
Sobrecarga de construtores é uma forma de dar ao usuário da classe a escolha sobre quais parâmetros deseja informar ao criar o objeto e quais deixar com valores padrão. Isso torna a classe flexível e fácil de usar.
Analogia:
Em um escritório de projetos se constroem automóveis. Alguém pede a configuração básica (sem ar-condicionado, só volante e rodas), alguém quer “luxo” (com aquecimento de bancos, Wi‑Fi e que o carro dirija sozinho). Mas o carro — ainda é a mesma classe; apenas diferentes maneiras de montá-lo!
Sobrecarga é quando em uma mesma classe são declarados vários construtores, mas com parâmetros diferentes (quantidade, tipo ou ordem de parâmetros). Todos têm o mesmo nome da classe e não possuem tipo de retorno.
Exemplo: classe com construtores sobrecarregados
public class Person {
String name;
int age;
// Construtor sem parâmetros (padrão)
public Person() {
this.name = "Desconhecido";
this.age = 0;
}
// Construtor com um parâmetro
public Person(String name) {
this.name = name;
this.age = 0;
}
// Construtor com dois parâmetros
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
Agora podemos criar objetos de maneiras diferentes:
Person p1 = new Person(); // nome = "Desconhecido", idade = 0
Person p2 = new Person("Vasya"); // nome = "Vasya", idade = 0
Person p3 = new Person("Petya", 25); // nome = "Petya", idade = 25
Como o Java decide qual construtor usar?
O Java observa a quantidade e os tipos dos argumentos que você passa após new. Se você escreve new Person("Vasya"), o compilador busca um construtor com um parâmetro do tipo String. Se você escreve new Person("Petya", 25), é necessário um construtor com parâmetros String e int.
2. Chamando um construtor a partir de outro: this(...)
Às vezes, ao sobrecarregar construtores, surge uma situação em que parte do código se repete. Por exemplo, você quer que todos os construtores definam obrigatoriamente o nome, e que a idade, se não informada, seja zero. Para não copiar a mesma lógica em cada construtor, é possível chamar um construtor a partir de outro com a palavra-chave this(...).
Exemplo
public class Person {
String name;
int age;
// Construtor com dois parâmetros
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Construtor com um parâmetro chama outro construtor
public Person(String name) {
this(name, 0); // chama Person(String name, int age)
}
// Construtor sem parâmetros chama outro construtor
public Person() {
this("Desconhecido", 0);
}
}
public Person(String name) {
this(name, 0); // chama Person(String, int)
}
Regra importante: a chamada a outro construtor com this(...) deve ser a primeira linha do construtor!
Por que isso é útil?
- Reduz a duplicação de código.
- Se você decidir alterar a lógica de inicialização (por exemplo, mudar um valor padrão), só será necessário alterar em um único lugar.
- O código fica mais limpo e mais fácil de manter.
3. Exemplos práticos: sobrecarga em uma classe real
Suponha que temos a classe Account — conta bancária. Às vezes sabemos apenas o nome do proprietário, às vezes queremos informar logo o saldo inicial e, em outras, também a moeda.
Exemplo de classe com construtores sobrecarregados
public class Account {
String owner;
double balance;
String currency;
// Construtor com três parâmetros
public Account(String owner, double balance, String currency) {
this.owner = owner;
this.balance = balance;
this.currency = currency;
}
// Construtor com dois parâmetros (moeda padrão — "EUR")
public Account(String owner, double balance) {
this(owner, balance, "EUR");
}
// Construtor com um parâmetro (saldo = 0, moeda = "EUR")
public Account(String owner) {
this(owner, 0.0, "EUR");
}
// Construtor sem parâmetros (proprietário — "Desconhecido", saldo = 0, moeda = "EUR")
public Account() {
this("Desconhecido", 0.0, "EUR");
}
public void printInfo() {
System.out.println(owner + ": " + balance + " " + currency);
}
}
Uso
public class Main {
public static void main(String[] args) {
Account acc1 = new Account("Ivan", 1000, "USD");
Account acc2 = new Account("Mariya", 500);
Account acc3 = new Account("Pyotr");
Account acc4 = new Account();
acc1.printInfo(); // Ivan: 1000.0 USD
acc2.printInfo(); // Mariya: 500.0 EUR
acc3.printInfo(); // Pyotr: 0.0 EUR
acc4.printInfo(); // Desconhecido: 0.0 EUR
}
}
Por que isso é conveniente?
- É possível criar objetos com diferentes níveis de detalhamento.
- Não é necessário informar todos os parâmetros sempre (especialmente se eles costumam ser iguais).
- É fácil expandir a classe: se surgir um novo parâmetro, é possível adicionar mais um construtor.
4. Erros comuns ao sobrecarregar construtores
Erro nº 1: confusão com tipos e ordem dos parâmetros.
Se você tem dois construtores — Person(String name, int age) e Person(int age, String name) — o compilador vai distingui-los, mas para o usuário da classe isso pode ser extremamente confuso. É melhor evitar tais situações.
Erro nº 2: ausência de construtor padrão.
Se você declarou apenas construtores com parâmetros e, depois, tenta criar um objeto sem parâmetros — ocorrerá um erro de compilação. Sempre adicione um construtor sem parâmetros, se ele for necessário.
Erro nº 3: tentar chamar outro construtor não na primeira linha.
A chamada this(...) deve sempre ser a primeira linha do construtor. Se houver algo antes disso — haverá erro de compilação.
Erro nº 4: encadeamento cíclico de chamadas de construtores.
Se um construtor chama a si mesmo (diretamente ou por meio de uma cadeia), isso levará a um erro de compilação devido a recursão infinita.
Erro nº 5: campos não inicializados.
Se você esquecer de inicializar algum campo no construtor (ou na cadeia de chamadas), o objeto pode acabar em um estado incorreto. Verifique se todos os campos têm valores significativos após a criação do objeto.
GO TO FULL VERSION