Fala Matheus, tudo bem ?
Por que você precisa de um segundo equals ? Repare que os dois tem exatamente a mesma implementação, com a diferença que um é de fato a sobrescrita do equals de Object e o outro é apenas um método comum da sua classe Aluno. Quem chama o equals por meio da referencia do tipo Aluno chamará o segundo, quem chama por meio da referência mais genérica Object chamará o sobrescrito.
Mas em ambos os casos o hashcode chamado será sempre o mesmo. Até testei aqui e funciona normalmente.
public static void main(String[] args) {
Object aluno = new Aluno("João");
Object aluno2 = new Aluno("João");
System.out.println(aluno.equals(aluno2));
System.out.println(aluno.hashCode());
System.out.println(aluno2.hashCode());
}
// Saida
//true
//2318353
//2318353
// objeto com mesmo conteúdo submetido a mesma função de hashcode = mesmo código de hash
Outra coisa, a implementação do equals não tem nenhuma proteção contra o risco de ClassCastException que pode ser lançado. Em geral as próprias IDEs tem recursos pra geração de equal e hashcode padrão a partir dos atributos que você quer envolver nas operações, e é recomendável sua utilização.
No caso do eclipse por exemplo, você pode usar ctrl + 3 => generate hashcode and equals.
Teríamos as seguintes implementações:
public class Aluno {
private String nome;
...
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((nome == null) ? 0 : nome.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Aluno other = (Aluno) obj;
if (nome == null) {
if (other.nome != null)
return false;
} else if (!nome.equals(other.nome))
return false;
return true;
}
}
Espero ter ajudado. Abraço!