Olá Maísa, tudo bem?
Excelente pergunta essa que você levantou aqui!
O conceito que estamos vendo nessa situação é como utilizamos o Polimorfismo, e é extremamente importante entender como ele pode ser útil para nós.
O exemplo que você trouxe é excelente para entendermos isso... então vamos lá...
Note que a classe Gerente herda da classe Funcionario, então todos os métodos e atributos que um funcionário possui, um gerente também irá possuir, certo?
Além disso, as subclasses (ou classes filhas), podem reescrever métodos da superclasse (ou classe mãe), como vemos no caso da bonificação do gerente, que é diferente dos demais funcionários.
Então o que acontece quando instanciamos um novo gerente dessa forma abaixo?
Funcionario g1 = new Gerente();
Será que perdemos os métodos da classe gerente por termos utilizado dessa forma?
O que acontece nesse caso, é que estamos utilizando uma variável de tipo mais genérico para armazenar uma referência ao objeto do tipo Gerente!
É isso que o Polimorfismo nos traz... a capacidade de um objeto poder ser referenciado de várias formas. Nesse caso poderíamos referenciar o objeto Gerente tanto como um Funcionario como um Gerente, pois o Gerente (subclasse) obrigatoriamente é também um Funcionario (superclasse).
OBS:(cuidado, polimorfismo não quer dizer que o objeto fica se transformando, muito pelo contrário, um objeto nasce de um tipo e morre daquele tipo, o que pode mudar é a maneira como nos referimos a ele).
O que pode acontecer de fato, é que talvez você "não consiga" acessar alguns métodos da classe Gerente num primeiro momento, se a utilizar dessa maneira.
O mais comum é que nessa situação você realmente utilize:
Gerente g1 = new Gerente();
Apenas em alguns poucos casos nós teríamos que utilizar a referência do tipo Funcionario, e nesses casos ainda assim poderíamos acessar os métodos da classe Gerente por meio de Casting, mas isso não é o mais comum, e também é mais trabalhoso.
Então em que caso isso seria útil para nós?
A situação que costuma acontecer é a que temos um método que recebe um argumento do tipo Funcionario:
class ControleDeBonificacoes {
private double totalDeBonificacoes = 0;
public void registra(Funcionario funcionario) {
this.totalDeBonificacoes += funcionario.getBonificacao();
}
public double getTotalDeBonificacoes() {
return this.totalDeBonificacoes;
}
}
Nesse caso criamos um método que tem como parâmetro um Funcionario. Para não reescrevermos o mesmo método mais de uma vez, podemos nos utilizar do Polimorfismo, passando todos os funcionários utilizando a referência mais genérica.
Esses conceitos podem ser bem difíceis de entender a primeira vista, é super normal... mas você está indo muito bem!
Com o treino e exercícios você vai pegar muito bem esse assunto, não se preocupe.
Te recomendo também ler a apostila da Caelum sobre Java e Orientação a objetos, pode te ajudar a entender mais a respeito de vários conceitos.
Apostila de Java - Caelum: Polimorfismo
Sempre que tiver dúvidas, pode contar conosco! 😉