Problema de OOP ou Java?

Olá a todos,

galera nao sei bem se esse seria mais o campo de atuação da OOP ou Java, as vezes parecem se fundir.
de qualquer forma eu ficaria muito feliz com ajuda. Pois bem ao problema:

vamos dizer que tenho essa hierarquia:

(A->B->C->D->E->F->G) (G extends F que extends E que extends D…)

na calsse A eu tenho um metodo assim:

class A{

public void Chama_reajuste(A qualquer) {

qualquer.getBonificacao();

}

public double getTotalDeBonificacoes() {
return this.totalDeBonificacoes;
}

}

e em B,C,D,E,F,G eu tenho o metodo:

getTotalDeBonificacoes(); // cada uma implementada de sua forma.

agora a duvida em si:

se na classe A eu chamar o metodo Chama_reajuste(A qualquer) e passar, tanto B,C,D,E…
mesmo o parametro desse metodo sendo do tipo A ele chamaria o getTotalDeBonificacoes da subclasse passada? tipo B,C,D,E… mesmo o parametro do metodo limitando o tipo a apenas A? mesmo sendo da mesma hierarquia, na minha cabeça se o Tipo é A ele pode nao enxergar os metodos da subclasse não?

muito obrigado!!

Não diria problema, mas um comportamento da jvm…

Tendo toda essa hierarquia, respondendo sua pergunta, a jvm ao ver uma chamada ao método getTotalDeBonificacoes() ela vai de “baixo pra cima” nas extensões, mesmo você indicando como parâmetro o tipo mais abstrato como na classe A por exemplo… se ela encontrar o método na classe E, vai executá-lo, se ele não foi sobrescrito (Override), sobe para D, senão sobe para C, …

Esse código:

class A{

    public void Chama_reajuste(A qualquer) {
        qualquer.getBonificacao();//a classe A não possui este método
    }

    public double getTotalDeBonificacoes() {
        return this.totalDeBonificacoes;//Também não possui este
    }
}

Não pode ser executado, pois os métodos chamados pela variável qualquer não existem na classe A.

Apenas para fins de exemplificação, compare com as seguintes implementações:

public class A {
    
    public void Chama_reajuste(A qualquer) {
        ((B)qualquer).getBonificacao();
    }

    public double getTotalDeBonificacoes() {
        return ((B) this).totalDeBonificacoes;
    }
}

Classe B extend A, e possui os métodos que estão sendo chamados em A por meio de conversão (casting):

public class B extends A{

    double totalDeBonificacoes;

    void getBonificacao() {
        //realiza uma operação
    }        
}

O objetivo é mostrar que para métodos inexistentes na classe Pai, você tem que realizar um casting, para a classe filha que possui aquele método.

Existe outro problema a ser considerando, se o método constasse na classe Pai, mas fosse privado, nenhuma classe filha poderia chama-lo.

Se o método for final, a classe filha pode acessar ele diretamente, mas não pode alterar o método para atender seu comportamento em particular.

São explicações limitadas, pois tem outros detalhes a serem levados em consideração a exemplo dos modificadores de acesso, public, private, protected, package.

O método getBonificacao() não foi declarado na classe A.

Este não precisa de casting, mas precisa da variável.

Na codificação abaixo eu errei, pois era uma variável e eu entendi como um método.

Obrigado pela contribuição @rodevops
:joy:

1 curtida

public void Chama_reajuste(A qualquer) {

qualquer.getBonificacao(); // não existe getBonificacao eu errei, seria getTotalDeBonificacoes

}

então nesse caso, com essa correção a jvm percorreria e execultaria o metodo da classe passada no parametro, mesmo sendo do tip A, digo ela ainda assim execultaria metodos da classe filha?

outra pergunta, que tbm é muito importante pra mim. Isso seria particular do java ou da OOP?

obrigado!

Eu percebi, por isso retirei meu comentário… mas vocês foram mais rápidos, malditos chineses! :joy:

Sim, desde que o método esteja declarado na classe pai, como você fez e acabou confundindo todo mundo entre ser getBonificacao, getBonificacoes etc :joy:

A OOP não obriga uma forma de implementar isso, mas se parar para analisar, a OOP copiou seu estilo da biologia, e nesse sentido, cada individuo evoluído da sua classe animal (classes filhas) deve executar ações (métodos) instintivamente (herança) e aprimorá-las (sobrescrita de métodos), logo, irei executar minhas ações aprimoradas e caso ainda não tenha aprimorado, buscarei dos meus ancestrais (método na classe anterior)… nossa viajei agora :joy:

Agora falando em código, o java examina duas coisas:

A objb = new B();

O que está antes do igual e o que está depois do new…

O que está antes é uma referência do tipo A e não um objeto como todo mundo fala/pensa…

Já o que está depois do new sim acaba se tornando um objeto, porém não manipulado diretamente (entra numa área de memória que não lembro o nome) e para ser acessada precisa ser pela referência (em linguagem c seria o ponteiro por exemplo)…

Tendo esses conceitos entendidos, quando se cria um método que pede uma referência, no caso…

public void Chama_reajuste(A qualquer) {
    ...
}

Você apenas está dizendo para o java “olha jvm, qualquer referência da classe A pode entrar aqui blz?”

Já quando você executa…

 qualquer.getTotalDeBonificacoes();

A jvm precisa ver qual new foi criado e a partir disso fazer toda aquela verificação que te falei…

Cara, desculpe se ficou muito extenso e se ainda não consegui ser muito claro, mas esses assuntos são longos para conversar…

1 curtida

Primeiramente, muito obrigado em me pelo tempo dedicado a minha duvida, elaborando estas respostas.

“A jvm precisa ver qual new foi criado e a partir disso fazer toda aquela verificação que te falei”

public void Chama_reajuste(A qualquer) {// o q parametro qualquer então tem que obrigadoriarmente ser instancia? tipo uma instacia de E ou qq outra da hierarquia?

}

Justamente para garantir que o método getTotalDeBonificacoes() está definido (nem que seja só na classe A) garantindo uma interface para sua implementação…

Você pode ter o mesmo comportamento usando interfaces, onde cada classe pode ser de um tipo diferente e não estar na mesma hierarquia, a diferença entre herança e interface é que na herança os métodos podem ou não conter uma implementação, já na interface você assina o famoso “contrato”, assumindo que irá definir o corpo do método (implementação) mas na interface ele é vazio…

Como falei é um assunto extenso e não vou me aprofundar em interfaces, procure se aprofundar primeiro em heranças e ver onde realmente são necessárias (cudado com extends apenas para ter código reaproveitável), depois disso você avança no esttudo de interfaces, mas por enquanto deixo um desafio para você correr atrás…

void validaLogin(Autenticavel usuario) {
    // ... critérios de avaliação
    Login login = usuario.longin(); // retorna usuario e senha por exemplo...
}

Imaginando um sistema com autenticação (login), onde posso ter como usuários o administrador, fornecedor e o cliente usando extends você poderia criar uma classe Pessoa e “encaixar” outras classes nelas certo?

Mas temos uma classe TiaDaLimpeza (por favor sem preconceitos ok? apenas uma ilustração) e ela não pode acessar o sistema, mas ela também é pessoa e agora, como resolver se não podemos extender?

Uma interface Autenticavel cairia muito bem

interface Autenticavel {
    public Login login(); // contrato a ser assinado...
}

Com isso qualquer classe que possa entrar no sistema pode “assinar” esse contrato, onde elas não seriam da mesma hierarquia… pronto paro por aqui, vai “matutando” ai e vê onde você consegue chegar e bons estudos!

Sem mais…
so quero agradecer a atenção recebida, pois enfim alcanço a paz mental inerente ao sanar de uma duvida, que me permitirar avançar nos estudo.

Abraços!!!

Sim. No caso do Java, o método chamado é sempre a versão do objeto, e não a versão da referência esse comportamento é chamado dynamic binding. Das linguagens que eu conheço, Java e C# funcionam dessa maneira. Em C++ é possível utilizar das duas maneiras: o comportamento default é chamar a versão do método correspondente ao tipo do ponteiro, esse comportamento é chamado static binding. Porém, ao se acrescentar a palavra virtual à declaração de um método ele passa a se comportar igual ao Java. Particularmente, eu não vejo muita utilidade em static binding.