Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Funcionario f = new Gerente(); não pode chamar métodos da classe Gerente?

Olá, pessoal! Achei que estava entendendo um pouco de polimorfismo até chegar na questão que pergunta porque o código abaixo não compila:

Funcionario f = new Gerente();
f.autentica(1234);

A resposta correta é que a "Quem define o que podemos chamar é a referência, que é do tipo Funcionario[...]". Mas como que isso ocorre sendo que nos exemplos do professor, a gente fez isso? No exemplo a gente cria Funcionario g1 = new Gerente() e depois de setar o salário, chamamos controle.registra(g1); que "entra" na classe Gerente pra poder fazer o calculo de sua bonificação corretamente. Se eu quisesse chamar o método setSenha() por ex pro g1 isso não seria possível uma vez que a referencia não é do tipo Gerente, mas sim do Funcionário?

6 respostas
solução!

Na sua primeira dúvida, quando chamamos o controle.registra(g1); não estamos entrando na classe gerente, e sim criando um objeto do tipo ''ControleBonificacao'' com o nome de ''controle''

ControleBonificacao controle = new ControleBonificacao();

E posteriormente invocando um método existente nesta mesma classe. Para a invocação deste método é necessário a inserção de um valor dentro do parênteses devido à forma que o construtor foi escrito:

    //código omitido

    public void registra(Funcionario f) {
        double boni = f.getBonificacao();
        this.soma += boni;

    }

ao chamarmos o controle.registra(g1);

estamos na verdade chamando o método registra e utilizando a referência g1 do objeto gerente que havíamos criado, para que o método realize as contas que nos fornecerão a bonificação da referência utilizada (no caso de g1) e é por esse motivo que quando chamamos controle.registra(g1); ela não está ''entrando'' na classe gerente.

O tipo de classe Funcionario ao lado da variável f dentro do método é o que chamamos de polimorfismo, e serve para que possamos utilizar uma referência genérica para acessar objetos mais específicos como o gerente (g1) ou o editor de vídeo (ev) e dessa forma poder utilizar apenas 1 método na hora de calcular a bonificação de todos funcionários.

Na segunda parte da sua dúvida, ao criarmos um objeto:

Funcionario g1 = new Gerente();

estamos criando um objeto com os atributos da Classe gerente, mas que é referenciado pelo tipo da classe Funcionário, logo apenas podemos chamar métodos que se encontram nesta classe, e como o método setSenha() se encontra na classe Gerente não é possível chamá-la assim como você havia dito.

Caso encontrem erros na minha explicação estou aberto a correções e espero ter ajudado.

Compartilho da mesma duvida da Monique.

Edit: Complementando : nessa aula no videod e resumo de herança a partir de 3:15 ele fala que esse exemplo poderia funcionar. Realmente fiquei mt confuso . HELP!

Essa é uma dúvida bem comum ao trabalhar com polimorfismo com tipagem estática.

Basicamente, temos que lembrar que as variáveis em Java guardam referências a Objetos e que o Compilador análise o seu código de acordo com o tipo declarado e não o tipo definido. Nesse caso, vc faz ambos em uma linha, vamos separar:

Funcionario f; // Declaração: existe uma referência f e ela aponta para um objeto do tipo Funcionario


f = new Gerente(); 
/*
* Definição: f agora aponta para um objeto do tipo Gerente (que é um subtipo de Funcionario)
* mas como declarado acima, o compilador só pode enxergar métodos e propriedades
* declarados na classe Funcionario
*/

A ideia é criar classes o mais genérico possível a fim de reaproveitar ao máximo o nosso código. Exemplo é o getBonificacao(), ele é declarado na classe Funcionario, então todas as subclasses o tem (é assim que o compilador vê). Uma subclasse pode sobrescrever (Override) um método, ou seja, redefini-lo. Assim, quando o método sobrescrito é invocado pela subclasse, o comportamento será o definido pela subclasse, essa é a vantagem do Polimorfismo. Podemos ter um mesmo método implementado de diversas formas. Por isso, classes abstratas e interfaces são muito usadas, elas permitem declarar métodos sem defini-los garantindo o polimorfismo.

Agora, se o método não é declarado na classe Mãe, apenas na filha, o compilador não tem como saber que o tipo mais genérico vai possuir aquele comportamento mais a frente no código. Pra isso, ele teria que analisar nosso código mais a fundo e, isso ele não faz. Mais a frente, será apresentado a Exception que são erros que podem ocorrer no momento da execução, esses erros o compilador não tem como prever.

Quanto ao fato de poder funcionar Miyashiroo, se o Java tivesse uma tipagem dinâmica como PHP, isso funcionaria sem problemas. Vc até consegue passar a referência para outra variável mais específica usando cast:

Funcionario f = new Gerente();
Gerente g = (Gerente) f;

Nesse caso, pegamos a referência f, criamos um objeto do tipo Gerente. Na segunda linha, passamos a referência para outra variável mas falamos para o compilador: eu sei que a referência f pode ser tratada como Gerente, faça isso. Entretanto, se fizermos isso:

Funcionario f = new Funcionario();
Gerente g = (Gerente) f;

O código também compila, mas na hora de rodar vai dar erro. Porque forçamos algo na etapa de compilação que não funciona no momento em que o código é executado.

Espero ter respondido, se tiver mais dúvidas. Estamos por aqui.

Abraços e bons estudos.

Aproveitando, caso queira alterar os atributos das classes que estendem a classe Funcionario você pode utilizar interfaces.

public interface MyInterface {

    public String alteraAtributoEspecifico(String s);
}

public abstract class Funcionario implements MyInterface {
}

public class Gerente extends Funcionario implements MyInterface {

    private String atributoEspecificoGerente;

    @Override
    public String alteraAtributoEspecifico(String s) {
        this.atributoEspecificoGerente = s;
        return this.atributoEspecificoGerente;
    }

    public class Testar {

    public static void main(String[] args) {

        Funcionario f = new Gerente();
        f.alteraAtributoEspecifico("Acessando Atributo do Objeto gerente pela referencia de Funcionário !!!);
        System.out.println(f);
    }

}

    

Fala Felipão! Mano o que me deixou confuso é o seguinte: Na aula antes desse exercício ele dá esse código: ` public class TesteReferencias {

public static void main(String[] args) {

    Funcionario g1 = new Gerente();

    g1.setNome("Rodrigo");
    g1.setSalario(5000);

    Funcionario f1 = new Funcionario();
    f1.setNome("Risos");
    f1.setSalario(2000);

    Funcionario ed = new EditorVideo();
    ed.setSalario(2500);

    ControleBonificacao controle = new ControleBonificacao();



    controle.registra(g1);
    controle.registra(ed);
    controle.registra(f1);

    System.out.println(controle.getSoma());



}

} ` E funciona, mas no exercício mesmo com o tipo mais genérico, a resposta fala q isso não roda. Mas eu acho que entendi o que aconteceu. Na questão ele supõe que o codigo do ControleBonificaçao não esteja com o tipo mais genérico ( funcionario) mas sim o mais especifico (gerente) e por isso não vai rodar mesmo. Obrigado pelas explicações galera, abriu a minha visão pra entender o todo. Mas ó negocio complicado kkkk Abraço!

Opa, Miyashiroo,

Esses são conceitos que vc vai se familiarizando com tempo. Na dúvida, sempre procure escrever um código pra tentar ver o que acontece, nesse área, quanto mais código diferente vc ler e testar, mais coisas vc aprende.

Abraços e bons estudos.