Uma breve explicação
Em Java, toda classe que NÃO extende outra classe, implicitamente, extende a classe Object.
Por exemplo:
abstract class Funcionario {}
class Diretor extends Funcionario {}
A classe diretor explicitamente extende Funcionario, logo, Funcionario é a superclasse direta de Diretor.
Já Funcionario não extende nada, logo, Object é, implicitemente, a superclasse direta de Funcionario.
Obs: Usei a palavra direta, pois indiretamente, todas as classes são subclasses de Object.
O método equals
A classe Object pertence à biblioteca padrão do Java e ela possui muitos métodos que nos auxiliam. Os métodos equals e toString são apenas 2 destes métodos.
O problema é que cada entidade do nosso programa possui um conceito diferente de igualdade e é por isso que precisamos sobreescrever o método equals.
Sobreescrever um método neste caso seria reimplementar na SUBCLASSE (Funcionario) um método existente na SUPERCLASSE (Object).
Agora me diga: O que faz um funcionario ser igual ao outro?
Na minha opinião, se o conjunto de atributos de um funcionario for igual ao de outro funcionario, eles serão iguais.
Assim, poderíamos implementar da seguinte forma:
abstract class Funcionario {
/* ... */
@Override
public boolean equals(Object o) {
// Retorna true se vc fizer algo como
// diretorA.equals(diretorA);
if (o == this) return true;
// Verifica se o é uma instancia da classe Funcionario, se NÃO, retorna false.
// Só lembrando que um objeto é uma instancia de uma classe.
if (!(o instanceof Funcionario)) return false;
Funcionario other = (Funcionario) o;
return this.nome.equals(other.nome)
&& this.matricula.equals(other.matricula)
&& this.cpf.equals(other.cpf)
&& this.anoAdmissao.equals(other.anoAdmissao)
&& this.salario == other.salario;
}
}
Há outras forma de se implementar isso, mas quis fazer da forma mais explicita possível pra vcs pegarem o jeito.
O método toString
O método toString é a representação do objeto em formato de texto. Considere o seguinte exemplo:
public class Main {
public static void main(String[] args) {
List<String> array1 = List.of("A", "B", "C");
List<Integer> array2 = List.of(1, 2, 3);
System.out.println(array1);
System.out.println(array2);
}
}
No console será impresso o seguinte:
[A, B, C]
[1, 2, 3]
Esta parte vcs podem fazer como quiserem. Como acham que um funcionário seria melhor representado? Vcs exibiriam apenas o nome? talvez o nome e a matricula?
Vou dar os exemplos.
abstract class Funcionario {
/* ... */
@Override
public String toString() {
return this.nome;
}
}
abstract class Funcionario {
/* ... */
@Override
public String toString() {
return this.nome + " " + this.matricula;
}
}
abstract class Funcionario {
/* ... */
@Override
public String toString() {
return this.nome + " " + this.matricula + " " + this.cpf;
}
}
Depois vc podem testar com algo assim:
Funcionario a = new Diretor();
a.nome = "João";
a.matricula = "111";
a.cpf = "111.111.111-11";
System.out.println(a);
Considerações finais
Vou deixar a parte dos contrutores pra vcs pesquisarem. Dei atenção à questão da sobreescrita dos métodos acima, pois acredito que são requisitos não tão óbvios pra quem está começando.
Espero que seja o suficiente pra vcs conseguirem progredir.