Qual a vantagem em sobrescrever um método em Java?

Obs: sou iniciante no assunto.
Qual a vantagem em subscrever um método em Java?
Por exemplo, temos o código abaixo para comparar:

        public boolean ehIgual(Conta outra){

        if(this.agencia != outra.agencia){
            return false;
        }
        if(this.numero != outra.numero){
            return false;
        }
        return true;
    }

Qual seria a vantagem de subscrever o método equals, nesse caso?

Pelo que entendi, vc está se referindo a sobrescrita de métodos, não “subscrita”.

Seu exemplo com equals() é um pouco complexo porque sempre que vc sobrescreve este método,
deveria também sobrescrever o método hashCode() de forma a manter o “Contrato Geral do hashCode”.

Vc pode ler mais sobre isso nos links abaixo:

Object#equals
Object#hashCode

De qualquer forma, sobrescrever o método equals() ao invés de usar o ehIgual()
faz com que seu programa esteja dentro dos padrões.

Todo desenvolvedor Java sabe que deve usar o equals() para comparar objetos,
usar um método diferente traria uma complexidade extra ao seu programa já que o
desenvolvedor deveria ficar atento a este detalhe.

Além disso há partes da biblioteca do Java que confiam neste padrão. Um exemplo disto
é a classe HashSet, ela funciona como um ArrayList só que não aceita elementos repetidos.

A forma como o HashSet determina se um elemento é repetido ou não é chamando, internamente, os métodos equals() e hashCode().

No código abaixo eu criei 2 classes: Autor e Livro.

Em Livro eu sobrescrevi os métodos equals() e hashCode() e em Autor eu criei o método ehIgual().

Também criei 2 HashSet para armazenar uma coleção de autores e uma coleção de livros.

Nos autores, repare como eu tentei adicionar um com o nome repetido. O mesmo eu fiz para os livros, tentei adicionar um com o título repetido.

import java.util.HashSet;

class Autor {
  String nome;

  Autor(String nome) {
    this.nome = nome;
  }

  @Override
  public String toString() {
    return this.nome;
  }

  public boolean ehIgual(Autor autor) {
    if (autor == null)
      return false;
    return this.nome.equals(autor.nome);
  }
}

class Livro {
  String titulo;

  Livro(String titulo) {
    this.titulo = titulo;
  }

  @Override
  public String toString() {
    return this.titulo;
  }

  @Override
  public boolean equals(Object livro) {
    if (livro == null)
      return false;
    if (livro instanceof Livro)
      return this.titulo.equals(((Livro) livro).titulo);
    return false;
  }

  @Override
  public int hashCode() {
    return this.titulo.hashCode();
  }
}

public class Main {
  public static void main(String... args) {
    HashSet<Autor> autores = new HashSet<>();
    HashSet<Livro> livros = new HashSet<>();

    autores.add(new Autor("A"));
    autores.add(new Autor("B"));
    autores.add(new Autor("A"));

    livros.add(new Livro("A"));
    livros.add(new Livro("B"));
    livros.add(new Livro("A"));

    System.out.println(autores);
    System.out.println(livros);
  }
}

Ao executar este código, perceba como a coleção de livros possui apenas 2 elementos,
apesar de eu ter adicionado 3. Ela não permitiu a inserção do livro com título repetido.

Já a coleção de autores possui os 3 elementos que eu adicionei.

O HashSet não deveria ter permitido que isso acontecesse, afinal é esperado que
ele não permita a inserção de elementos repetidos. Porém, a classe Autor não
honrou o contrato exigido para que o HashSet funcionasse como esperado.

Viu como é importante seguir os padrões?

1 curtida

Oi! Obrigada por esclarecer…
Desculpa ainda sou bem leiga no assunto, mas no material que eu to estudando, não usou o hashCode() e tá rodando normalmente. Sabe dizer pq? E nesse caso que não foi usado o hashCode(), qual seria a vantagem em sobrescrever o equals?

    public class  Conta {
		private int agencia; 
		private int numero;

	     public Conta(int agencia, int numero) {
		}

		@Override
	        public boolean equals(Object ref){

	            Conta outra = (Conta) ref;

	            if(this.agencia != outra.agencia){
	                return false;
	            }

	            if(this.numero != outra.numero){
	                return false;
	            }

	            return true;
	        }
	}


import java.util.LinkedList;

	public class TesteArrayList {
		
		public static void main(String[] args){

		    LinkedList<Conta> lista = new LinkedList<Conta>();

		    Conta cc1 = new Conta(22, 22);
		    Conta cc2 = new Conta(22, 22);

	             boolean igual = cc1.equals(cc2);
		     System.out.println(igual); 
		     
		}
	}

Não somos obrigados a sobrescrever hashCode(). Devemos sobrescrever os 2 apenas se quisermos honrar o contrato que mencionei.

No código que eu mostrei, experimente remover o equals() ou o hashCode(), ou os 2 de uma vez, da classe Livro. Vc verá que o código compilará e rodará normalmente, mas o HashSet não se comportará como esperado, isto é, não impedirá a inserção de elementos repetidos.

No material que vc está estudando só foi implementado o equals() porque implementar o hashCode() não era relevante para o que estava sendo ensinado.

Mesmo assim é importante sobrescrever o equals() ao invés de criar um ehIgual(), mesmo que seja apenas um exercicio e mesmo que só vc vá usar o código, porque assim vc aprende a seguir o padrão desde já.

Uma coisa a ter em mente é o seguinte:

O equals() é um método como outro qualquer. Vc poderia criar um método com o nome que quiser para verificar se um objeto é igual ao outro. Porém, este método com um nome qualquer não estaria seguindo a convenção que foi estabelecida no mundo Java e, se sua classe for usada em conjunto com algumas funcionalidades da biblioteca padrão, as coisas não funcionarão como esperado como ilustrei usando a classe HashSet como exemplo.

Já pensou como seria ruim se cada classe tivesse um método diferente para verificar igualdade? Seria bem complicado