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

Dúvida na criação de variáveis

Pessoal, acho que não entendi direito, então se alguém puder me ajudar, agradeço!

Conta cc = new ContaCorrente();

A váriavel cc vai ser do tipo Conta e vai receber uma referência do objeto ContaCorrente. Entendo que isso funciona pois ContaCorrente é uma Conta.

Minha dúvida é: se cc na verdade é apenas um ponteiro e não o objeto, que diferença faz o tipo dela?

7 respostas

O tipo da referencia vai determinar quais metodos vc pode chamar naquele objeto. Por isso ele é importante.

Entao se vc tem uma referencia do tipo Conta, só metodos de Conta podem ser chamados. Se ContaCorrente eventualmente tem um metodo a mais especifico dela, ele nao pode ser chamado.

Conta cc = new ContaCorrente();
cc.metodoEspecificoDeContaCorrente(); // nao compila

Agora realmente a vantagem de vc poder usar referencias do tipo mãe (polimorfismo) não fica obvio nessa linha simples Conta cc = new ContaCorrente();. Realmente aqui nao ha mto motivo, podia ter feito logo ContaCorrente cc = new ContaCorrente();

A vantagem do polimorfismo aparece quando, por exemplo, vc faz um metodo que recebe Conta e ai pode passar todo tipo de conta pra ele, indistintamente:

// metodo
void fazAlgo(Conta c) { ..... }

// chamada
ContaCorrente cc = new ContaCorrente();
ContaPoupanca cp = new ContaPoupanca();

fazAlgo(cc);
fazAlgo(cp);

Pois é, mas aí dentro da função eu vou precisar fazer o cast pro tipo correto se quiser usar algum método específico.

Isso da variável ser apenas um ponteiro, mas um ponteiro que possui características (atributos e métodos) que serão deles independente do objeto que ele referência que não faz sentido pra mim. É como se ao invés de armazenar uma referência, a variável armazenasse o próprio objeto.

Não é simplesmente a questão de apontar uma referência. Pois estamos falando de classes e herança. Quando um objeto é do tipo Conta e recebe uma referência a ContaCorrente, há uma relação que precisa ser avaliada. Pois em alguns casos do Polimorfismo, pode lhe trazer vantagens nas soluções dos problemas. Acredito que pode não lhe fazer sentido, pensando nessa lógica do funcionamento teórico. Sugiro levar para um caso real de modelagem.

Oi Cleiver,

Realmente se vc quiser chamar um metodo especifico de ContaCorrente ai nao faz sentido seu metodo receber qualquer Conta (casting é a excecao da excecao, idealmente vc nunca faria casting).

Ter o momento "Aha" do polimorfismo é um passo bem complicado mesmo no aprendizado de orientação a objetos, fique tranquilo. Mas é bem importante. Polimorfismo é um dos alicerces de OO e muito, mas muito útil na pratica, acredite.

Deixa eu tentar elaborar o exemplo do método que recebe Conta pra ver se vc acha bacana:

Imagina que quero fazer um método que soma o saldo de um monte de contas. A classe Conta possui um getSaldo que é herdado por ambas as classes ContaCorrente e ContaPoupanca. Cada uma delas pode ter metodos especificos, mas o que quero apenas somar o saldo, e eu sei que ambas possuem getSaldo porque herdam de Conta.

Graças ao polimorfirmo eu posso fazer um método soma que recebe um array de Conta e faz a conta pra mim:

double soma (Conta... contas) {
    double saldo = 0.0;
    for (Conta c : contas) {
        soma += c.getSaldo();
    }
    return soma;
}

É muito forte isso de que eu posso chamar esse método passando objetos de varios tipos filhos especificos: ContaCorrente, ContaPoupanca, ContaInvestimento etc:

ContaCorrente cc1 = new ContaCorrente();
cc1.deposita(1000);
ContaCorrente cc2 = new ContaCorrente();
cc2.deposita(1000);
ContaPoupanca cp1 = new ContaPoupanca();
cp1.deposita(500);
ContaPoupanca cp2 = new ContaPoupanca();
cp2.deposita(500);

double somaFinal = soma(cc1, cc2, cp1, cp2);

Imagine por um momento que não existisse polimorfismo. Como eu somaria o saldo de um punhado de ContaCorrente e um punhado de ContaPoupanca?

Como não tem poliformismo, meu método não pode receber Conta. Entao preciso fazer um que recebe ContaCorrente apenas:

double somaCC (ContaCorrente... contasCorrente) { ... }

E outro que recebe ContaPoupanca:

double somaCP (ContaPoupanca... contasPoupanca) { ... }

Acabo de duplicar minha logica, infelizmente. Mas nao so isso, na hora de chamar preciso lembrar de chamar os dois:

double somaFinal = somaCC(cc1, cc2) + somaCP(cp1, cp2);

E a gente pode ate pensar que isso nao é um grande trabalho. Mas e se tenho um terceiro tipo de Conta, ContaInvestimento? E depois um ContaEmpresa? E etc.

Quando usamod polimorfismo lá em cima, não precisamos nos preocupar com nada disso. É muito melhor :)

solução!

É uma dúvida muito mais voltada à Orientação a Objetos, do que à Linguagem Java, então não vou inserir código.

Somente para acrescentar um ponto de vista:

Pense na referência do objeto como um controle remoto de uma tv, e o objeto é a TV em si. Mesmo que a TV seja bem avançada (como uma Smart TV), se você usar um controle remoto genérico e simples, ele vai conter somente funções básicas e genéricas de TVs (mudar canal, ligar, aumentar volume) e você não terá acesso às funções específicas do objeto (Smart TV), como acesso à internet, por exemplo.

Mas embora possa parecer ruim a princípio, o uso de referências mais genéricas traz muitas vantagens nas Linguagens OO.

Ótima pergunta, é muito importante sabermos os conceitos que diferem Objetos de Referências a Objetos!

Obrigado pela resposta, pessoal!

Eu entendi a parte da utilidade para o polimorfismo. Minha questão fica mais clara com esse exemplo do controle remoto que o Igor deu.

Sempre é bom exercitar esta lógica da modelagem e refatoração. Gratidão pelos exemplos! Sergio muito esclarecedora e detalhada sua resposta, valeu.