W3docs

Sobrecarga de Métodos em Java

Defina vários métodos com o mesmo nome mas parâmetros diferentes em Java para criar APIs flexíveis.

Sobrecarga de métodos consiste em declarar dois ou mais métodos na mesma classe com o mesmo nome mas listas de parâmetros diferentes. O compilador escolhe qual deles chamar com base nos tipos dos argumentos passados.

Você já usou métodos sobrecarregados sem perceber. System.out.println(...) tem versões que recebem int, double, String, Object, char[], entre outros. Todos se comportam de forma semelhante — imprimem o valor e uma nova linha — mas a implementação difere de acordo com o tipo.

O que significa "lista de parâmetros diferente"

Duas sobrecargas devem diferir em aridade (número de parâmetros) ou nos tipos desses parâmetros em ordem. Não é suficiente diferir apenas em:

  • Nomes dos parâmetros
  • Tipo de retorno
  • Se os parâmetros são final
public static int square(int n) { return n * n; }

// VALID overloads — different parameter types
public static double square(double n) { return n * n; }
public static long   square(long   n) { return n * n; }

// VALID overload — different arity
public static int sum(int a, int b)             { return a + b; }
public static int sum(int a, int b, int c)      { return a + b + c; }

// INVALID — only the return type differs
// public static long square(int n) { return (long) n * n; }   // won't compile

Como Java escolhe uma sobrecarga

Quando você escreve square(3), o compilador faz isso na seguinte ordem:

  1. Correspondência exata. Existe uma sobrecarga cujos parâmetros correspondem exatamente aos tipos dos argumentos? square(3)square(int). Pronto.
  2. Alargamento. Se não, os argumentos podem ser alargados (por exemplo, int → long, int → double)? Escolhe a sobrecarga que exige o menor alargamento.
  3. Autoboxing / unboxing. Caso contrário, tenta embalar ou desembalar (int ↔ Integer).
  4. Varargs. Como último recurso, recorre a uma sobrecarga varargs (veja o capítulo sobre varargs).

Se duas sobrecargas empatam no mesmo passo, a chamada é ambígua e não compilará.

public static void show(int n)    { System.out.println("int: " + n); }
public static void show(long n)   { System.out.println("long: " + n); }
public static void show(double n) { System.out.println("double: " + n); }

show(3);     // exact match → int
show(3L);    // exact match → long
show(3.0);   // exact match → double
show((short) 3);   // widens short → int (closest), picks show(int)

Ambiguidade

Quando o compilador não consegue decidir entre duas sobrecargas igualmente boas, ocorre um erro:

public static void f(int a, long b)  { /* ... */ }
public static void f(long a, int b)  { /* ... */ }

f(1, 2);   // ERROR: reference to f is ambiguous

Ambas as sobrecargas exigem o alargamento de um argumento de int para long. Nenhuma é "melhor". A solução é desambiguar no ponto de chamada com uma conversão explícita — f(1, 2L) ou f(1L, 2) — ou adicionar uma terceira sobrecarga f(int, int) que trata o caso exatamente.

Sobrecarga em tipos de objeto

Os tipos de referência sobrecarregam da mesma forma, mas com relações de subtipo em vez de alargamento:

public static void log(Object o) { System.out.println("Object: " + o); }
public static void log(String s) { System.out.println("String: " + s); }

log("hello");        // exact match → String
log(42);             // autobox to Integer, then Integer is-a Object → log(Object)
log((Object) "hi");  // forces the Object overload

Se você passa uma String e a única sobrecarga aceita Object, Java aceita — String é um Object. Mas se houver uma sobrecarga mais específica, Java a prefere.

Quando a sobrecarga é útil

O objetivo da sobrecarga é oferecer aos chamadores uma API limpa e natural para o tipo. Dois padrões surgem com mais frequência:

Valores padrão. Uma sobrecarga curta chama a longa com valores padrão sensatos:

public static void greet(String name) {
  greet(name, 1);                 // delegate
}

public static void greet(String name, int times) {
  for (int i = 0; i < times; i++) {
    System.out.println("Hello, " + name);
  }
}

Conversores de conveniência. Diferentes tipos de entrada, mesma operação lógica:

public static int lengthOf(String s) { return s == null ? 0 : s.length(); }
public static int lengthOf(int[] xs) { return xs == null ? 0 : xs.length; }
public static int lengthOf(int n)    { return Integer.toString(n).length(); }

O chamador escreve lengthOf(x) sem se preocupar; o compilador encaminha para o corpo correto.

Quando não sobrecarregar

Se duas sobrecargas fariam coisas substancialmente diferentes, dê-lhes nomes diferentes. O leitor de format(x, y) não deve precisar descobrir qual sobrecarga foi escolhida para entender o que a chamada faz. Sobrecargas devem ser variações da mesma ideia, não ideias diferentes compartilhando um nome.

Sobrecarga vs. sobreposição

Esses dois termos soam parecidos, mas resolvem problemas diferentes, e confundi-los é a fonte mais comum de confusão.

  • Sobrecarga é mesmo nome, listas de parâmetros diferentes, dentro de uma única classe. Qual método é executado é decidido pelo compilador, olhando apenas para os tipos estáticos (declarados) dos argumentos. Isso é chamado de vinculação estática (em tempo de compilação).
  • Sobreposição é mesmo nome, mesma lista de parâmetros, em uma subclasse — substituindo um método herdado. Qual método é executado é decidido pela JVM em tempo de execução, com base no tipo real do objeto. Isso é vinculação dinâmica (em tempo de execução).
Object x = "hello";
log(x);   // calls log(Object), NOT log(String) — chosen from x's DECLARED type

Mesmo que x contenha uma String em tempo de execução, o compilador só vê Object x, então escolhe a sobrecarga de Object. A seleção de sobrecarga nunca olha para o tipo em tempo de execução — essa é a função da sobreposição. Veja sobreposição de métodos para o lado em tempo de execução da história.

Um exemplo prático

java— editable, runs on the server

O que vem a seguir

A sobrecarga permite que um nome aponte para vários métodos. Às vezes você quer um único método que chame a si mesmo — resolvendo um problema ao separar uma parte e pedir a uma versão menor do mesmo problema que trate do restante. Isso é recursão.

Prática

Prática
Qual diferença entre dois métodos NÃO é suficiente para torná-los sobrecargas válidas?
Qual diferença entre dois métodos NÃO é suficiente para torná-los sobrecargas válidas?
Was this page helpful?