Bem estou quebrando a cabeça já li livros mas estou achando bastante complicado o conceito de polimorfismo alguém com paciência pode me explicar como ocorre o processo…??? a idéia que eu tenho é.
qual a relação de polimorfismo que ocorre entre essas classes???
o que eu notei que a classe Manifero é herdeira da classe animal
e ambas tem o procedimento alimentar é essa a idéia de polimorfismo…???
sim… polimorfismo: quando se reescreve um método implementado na classe Pai.
A
Adriano_Almeida
Ãhn??? Isso se chama Override.
Polimorfismo em suma é referenciar uma classe derivada como se fosse a classe pai!
A
arthurnn
o interessante de polimorfismo é voce saber que toda ave e mamifero é um animal… entao na hora de instaciar essas classes voce deve fazer assim:
Animalcachorro=newMamifero();
voce naum levaria em conta o polimorfismo se voce fizesse assim:
Mamiferocachorro=newMamifero();
Isso ocorro porque futuramte se voce for precisar de um animal qualquer de parametro de um metodo! voce podera usar um mamifero ou uma ave.
se nao voce naum poderia colocar um animal como paremetro e sim escolher ou mamifero ou ave.
naum sei se ficou bem explicado…
vlww!!
E
edymrex
p/arthurnn
cara vc foi objetivo sim mais não tenho certeza se eu entendi o que
eu compreendi e que poliformismo e quando vc quer referenciar uma classe
derivada por uma classe pai vo colocar um exemplo pra ver se eu entendi mesmo exemplo:
entao tome cuidado para naum inverter… sempre a classe mae eh q vai vir sendo declarada ex:
Cavalo s = new Burro();
pois o jeito de se pensar eh que " todo burro é um cavalo "
obs: nunca eskeca de por ‘()’ pois ele naum ira chamar o construtor da classe e naum ira funcionar.
entaum e sobre o metodo come() voce tem q pensar assim… o metodo come() no burro é igual ao do cavalo? se for voce naum presica faze-lo de novo na classe burro!!pois ele herda o metodo da classe mae, se ele for diferente na classe filha entaum voce ira fzer otru metodo come() na classe burro q ira SOBREESCREVER o metodo da classe mae!
E
edymrex
valew cara ajudou bastante
A
arthurnn
haha qualquer coisa eh soh perguntar… eu tambem estou começando nos estudos agora… isso eu aprendi semana passado!!! so que como estou estudando no trabalho tenho bastante gente aqui para me explicar…
flww!!
L
LPJava
polimorfismo signigica muitas formas… isso vc ja sabe vou explicar de uma forma que entendi porem quebrei a cabeça…
quando vou usar polimorfismo…hahah depende de seu problema meu amigo. .isso vc q vai analisar seu problema e ver se pode usar o conceito de polimorfismo…mais vamos la… entender como ele funciona…
você tem uma class chamada banco e dentro dessa class vc tem varioas serviços que a class oferce, seguro de vida, titulos, contas correntes, conta poupança, cartao de credito etc. blz? nao pense na forma tecnica de chama entenda a essencia depois implemente…
se entendeu isso o resto é moleza la vai…
Vamos dizer que tem dois novos clientes um quer conta correte e outro que conta poupança…entao nessas contas temos os mesmo metodo por exemplo saldo(), saque(), deposita(), porem as vezes com implementacoes um pouco diferente na poupanca qdo for sacar ela nao pode cobrar nenhuma taxa e a corrente cobra seria uma implementação diferente mais a forma de deposito é o mesmo no eh? so muda que na hora vc diz to depositando na o real na corrente e nao na poupança… mais como o dinheiro vai entrar eh = pega o valor depositado e soma com seu saldo atual. para ter um novo saldo…
entao ai vc tem muitas ou seja o metodo saldo(), saque() pode gerar muitas formas… entao ai temos polimorfismo… muitas formas… o ponto é que vc nao precisa escrever o metodo novamente… apenas realizar algumas novas implementações para a devida classe mais nada…
espero ter ajudado com esse simples exemplo qualquer duvida so postar
A
albiere
Ãhn??? Isso se chama Override.
Polimorfismo em suma é referenciar uma classe derivada como se fosse a classe pai!
nohhh cara… viajei msm… o trem ta feio msm… kkkk…
vlw por me corrigir… :oops:
L
lalesan
arthurnn, acho que vc tá misturando tudo (herança com polimorfismo)…
isso aí é herança, a vantagem do polimorfismo (explicado pelo camilolopes) - e não poliformismo - é q pode acontecer de vc ter o burro com filha de cavalo, e come() diferente em cada um, tipo, vc criou class burro extends cavalo, mas sobreescreveu “come” em burro (por exemplo, em “cavalo” come retorna “ração p/ cavalo” e em burro, “ração p/ burro”), aí vc tem um função que tem como parâmetro “burro” (public void Comida(Burro burro)) q retorna “burro.come” (esse burro aqui é parametro hein! pq tá dentro da função); se vc em algum lugar fizer Cavalo burro1 = new cavalo() e passar esse burro1 com parâmetro em comida, vc vai ter como retorno “comida p/ cavalo”, mesmo q nessa função esteja “burro.come”, pq o burro1 q eu passei é na verdade um cavalo, o resultado depende da classe q vc tá passando… e parafraseando o camilo:
camilolopes:
ai temos polimorfismo… muitas formas…
acho que é isso, tomara q eu não tenha complicado tudo…
A
arthurnn
simsim!! vlw por complementar
M
Mantu
Polimorfismo, ao pé de letra, é assumir várias formas. O polimorfismo se manifesta quando temos uma variável de tipo A que referencia um objeto de tipo B, sendo que A é a classe pai/avô/bisavô/etc de B, e a partir da variável citada, invocamos um método previsto em A, mas sobrescrito por B. Confuso? Vamos destrinchar isso.
.
[color=green]Primeiro de tudo, herança:[/color]
Quando uma classe B herda uma classe A, todos os membros (métodos e campos) publicos ou protegidos de A passam a fazer parte de B. Por exemplo, imagine as seguintes classes (Se o Deitel ver isso, vai me processar :lol: ) :
Aqui o link para as classes: Empregado.java Horista.java Comissionado.java
Desse jeito, poderíamos muito bem fazer algo do tipo:
packagehelp.guj.puppets.polimorfismo.folha;publicclassTeste1{publicstaticvoidmain(String[]args){Horistahorista=newHorista();horista.setNome("Zé");horista.setSobrenome("das Couves");horista.setSalarioHora(12.52);System.out.println("O "+horista.getNome()+" "+horista.getSobrenome()+" tira R$"+horista.getSalarioHora()+" por hora!!!");}}
embora os métodos setNome, setSobrenome e setCpf não estejam declarados na classe Assalariado, eles “estão ali”, pois Assalariado herda todos os métodos e campos publicos ou protegidos de Empregado.
Mas herança é mais do que isso! Herança tem toda uma carga semântica, não é apenas um meio de você poupar código reaproveitando métodos e campos de uma classe pai(superclasse) nas classes filhas(subclasses). Não convém por exemplo criar uma classe Ave e fazer esta ser pai de uma classe Aviao, só porque ambos voam… Deve haver algum sentido na relação de herança. Classes envolvidas em relaçoes de herança devem atender ao critério É-UM. Uma objeto de uma classe filha É-UM objeto da classe pai. Um HoristaÉ-UMempregado. Sacou?
.
[color=green]Agora vamos falar um pouco sobre métodos sobrescritos. [/color]
Você deve ter notado que na classe Pai temos um método chamado toString. A princípio, sabemos que esse método estari disponível para as classes filhas Horista e Comissionado. Porém, ambas têm tembém um método toString com a mesma assinatura!!! Isso não dá pau? Não! Isso é o que chamamos de sobrescrever método. As classes filha estão “passando por cima” da implementação do método toString imposta pela classe pai. Isto quer dizer que, se invocarmos toString a partir de ama variável do tipo Horista, por exemplo, o toString que será executado é aquele escrito na classe Horista, e não o que foi escrito na classe Empregado.
.
[color=green]Vamos ver um pouco sobre classes e métodos abstratos.[/color]
Na programação OO, criamos classes com o intuíto de representar algum conceito da vida real (Cachorro, pessoa, televisão, carro, empregado, etc…) ou então algum conceito teórico (Listas, filas, pilhas, árvores, matrizes, etc…). Recorremos a herança para criar relações de generalização/especialização entre conceitos que mantêm entre si um certo laço “familiar”. No exemplo que estamos utilizando aqui, temos o conceito de empregado - representado pela classe Empregado - que generaliza os conceitos de empregado assalariado e empregado horista - representados pelas classes Comissionado e Horista, respectivamente. Da mesma forma, Comissionado e Horista especializam, cada uma a seu modo, o conceito de Empregado.
É facil para nós imaginarmos um funcionário, por exemplo, comissionado: É um empregado que tem nome, sobrenome, cpf e recebe um vencimento que é calculado da seguinte forma: um salário base adicionado de um percentual sobre suas vendas a título de comissão. Temos informações suficientes para “concretizar” o conceito de empregado comissionado. Mas, e se tentarmos imaginar um empregado? Assim, um fulano que só sabemos que é empregado? Bom, sabemos que o cara tem um nome, um sobrenome, um cpf e recebe um vencimento. Mas, não sabemos como que se dá esse vencimento, pois esse cálculo depende da especialização deste empregado… Se ele é horista, os vencimentos são calculados de um jeito, se é comissionado, de outro, e por aí vai. O conceito empregado mostra-se um tanto genérico, abstrato… Faz sentido ter um empregado horista, ou um empregado comissionado, mas não faz muito sentido ter um puro e simples empregado, fica meio vago… Se fossemos o Java, faria sentido termos uma instância de Horista[i] ou de Comissionado, mas não faria sentido termos uma instância de Empregado.
Como então podemos evitar que se crie instancias non-sense de classes que representam conceitos vagos? Simples! Declaramos que a tal classe é abstrata utilizando a palavra chave abstract (vago, genérico, abstract… sacou? :XD: ). Perceba que a classe Empregado é uma classe abstrata, pois não sabemos como calcular os vencimentos de um determinado funcionário. Uma classe declarada abstract não pode ser instanciada. Ela pode sim ter construtores, mas você não pode fazer isso:
Empregadozequinha=newEmpregado();
Isso aí vai dar erro de compilação, reclamando que a classe Empregado não pode ser instanciada.
Como vimos, não temos como saber a forma de calcular os vencimentos de um simples Empregado. Porém, sabemos que todo empregeda recebe um vencimento, independente da forma como este é calculado. Isso nos faz pensar que precisamos de um mecanismo que garanta que toda e qualquer subclasse instanciável de Empregado tenha uma implementação para o cálculo de vencimentos, mesmo porque o escravagismo já foi abolido há um bom tempo… Esse mecanismo em Java se dá através de métodos abstratos, que são métodos declarados com o a palavra chave abstract. Estes métodos não devem ter corpo. Todo o seu bloco de instruções, incluindo os colchetes deve ser substituído por um “;”. Veja por exemplo o método vencimentos na classe Empregado
publicabstractdoublevencimentos();
Ao invés de um corpo de método( “{ … }” ) ele tem um “;”. Isto é obrigatório, pois um método abstrato indica às subclasses que elas devem implementar este comportamento e que a superclasse não fornesse uma implementação padrão para este comportamento.
Uma classe abstrata pode ter métodos não-abstratos, como podemos ver na classe Empregado. Aliás, uma classe não precisa ter um ou mais métodos abstratos para poder ser também abstrata. Faça o teste! Veja se por acaso isso aqui não compila aí na sua máquina:
Funcionou, né? OK! Mas, por outro lado, se uma classe tem um ou mais métodos abstratos, ela deve, obrigatoriamente, ser declarada como classe abstrata. Não acredita? Pegue então a classe Empregado e experimente compilá-la depois de retirar ou comentar o abstract da declaração da classe:
public/*abstract*/classEmpregado{...
Com certeza isso não vai compilar. O seu compilador vai reclamar, dizendo que um método abstrato só pode ser declarado em classes abstratas. Pra resumir: Uma classe não precisa declarar método(s) abstrato(s) para ser abstrata, mas uma classe que declara método(s) abstrato(s) deve ser declarada como abstrata. Um último detalhe a respeito dos métodos abstratos: eles nunca podem ter acesso privado ou acesso de pacote. Tente pensar no por quê…
Todo esse papo sobre métodos e classes abstratas traz uma consequência interessante quando pensamos em herança envolvendo uma classe que de fato tenha métodos abstratos: Se a herança faz com que as subclasses incorporem todos os membros públicos e protegidos, então um método abstrato, eventualmente declarado por uma superclasse, vai se propagar, “estar presente” na subclasse. E agora? Quer dizer então que minha subclasse vai ter que ser abstrata também??? Não, necessariamente… Quando uma subclasse herda de uma superclasse um método abstrato, a “casa cai pra ela”. Ela fica com apenas duas opções:
:arrow: Ou essa subclasse vira uma classe abstrata
:arrow: Ou então essa subclasse provê uma implementação para o método abstrato herdado.
Não tem por onde correr! Tem que atender a uma, e somente uma, destas duas alternativas.
O caso mais trivial é quando a subclasse se torna também abstrata, jogando o “pepino” pra uma eventual subclasse sua. Perceba que somente haverá uma classe instanciável nessa árvore de herança quando alguma subclasse resolver implementar o(s) método(s) abstrato(s) herdado(s).
A outra alternativa, implementar o método abstrato, se dá quando uma subclasse sobrescreve o método abstrato. No nosso caso, a coisa não se extendeu muito. Tomemos como exemplo a classe Comissionado: A classe Empregado tem o método abstrato vencimentos, que é herdado e então sobrescrito pela classe Comissionado. Ou seja, a subclasse Comissionado está implementando o método abstrato herdado da superclasse Empregado. Assim, Comissionado se torna uma classe instanciável.
.
[color=green]Já ouviu falar sobre upcasting e downcasting? Não? Então vamos lá.[/color]
Lembra daquela semantica que mencionamos a respeito da herança? Aquele papo do é-um? Pois então. Podemos muito bem tratar um objeto de uma classe filha como se fosse um objeto da classe pai. Veja:
Empregadoemp=newComissionado();
Esta instrução é totalmente permitida. Pois, afinal de contas, um Comissionado é um Empregado. Chamamos esse tipo de atribuição - um objeto de classe filho à uma variável do tipo da classe pai - de upcasting, quando nós “subimos” a árvore de heranca. Em um upcasting, existe a garantia de que a subclasse tem, no mínimo, todos os métodos que a superclasse tem. Porém, a variável que recebeu uma instância de uma subclasse, só poderá acessar a parte comum entre ?pai? e ?filha?. No nosso exemplo acima, a variável emp acessaria apenas os métodos (get/set)Nome, (get/set)Sobrenome, (get/set)Cpf, toString e vencimentos. Isso é possível porque tudo que está previsto na superclasse é coberto pela subclasse. Pense sempre na subclasse como uma extensão (daí a palavra chave extends) da superclasse.
Em oposição ao upcasting, existe o conceito de downcasting. Você faz um downcasting quando “desce” a arvore de herança. Porém, o downcasting deve ser praticado com atenção, pois ele tem algumas restrições e armadilhas. Vamos usar um exemplo bem simples e intuitivo para vislumbrar isso. Imagine que temos uma superclasse chamada Quadrilatero e algumas de suas subclasses, tais como Retangulo e Trapezio. Começemos por um upcasting:
Quadrilateroquad=newRetangulo();
Já vimos que isso é sempre permitido e sem restrições - desde que o objeto instanciado seja de uma subclasse da classe da variável quad, evidentemente. Um retângulo é um quadrado também.
E se quisermos reverter o processo? Pegar aquele objeto Retangulo referenciado pela variável quad e referenciá-lo com uma outra variável, só que do tipo Retangulo? Intuitivamente, fariamos algo assim:
Retanguloret=quad;
Isso simplesmente não vai compilar.
Opa! Alto lá! Nós quem, cara-pálida? Um humano que lê o seu código
De fato sabe que ali, “debaixo do quad”, tem um objeto Retangulo. Mas o Java não tem como saber isso… O Java não tem como ler a instrução anterior e interpretar que “debaixo do quad” tem, de fato, um objeto Retangulo. Pra fazer o downcasting você, programador, precisar informar o Java sobre o que “se esconde” sob a variável quad. Fazemos isso dando um cast na variável quad para o tipo Retangulo:
Aí sim, informamos ao Java quem está lá debaixo! Beleza! Só tem um porém: E se por acaso nem mesmo nós soubermos qual a subclasse de um objeto que está “escondido” sob uma variável cujo tipo é a superclasse?
Ah é, sabichão? Então, engole essa aqui ó:
1/**2 * @author Mantu3 */4packagehelp.guj.puppets.polimorfismo.simples;56importbr.com.autbank.tech.util.math.RandomBetween;78publicclassTesteQuadrilateros{9publicstaticQuadrilateroalgumQuadrilateroQualquer(){10Quadrilateroresult;1112if(RandomBetween.getInt(-100,100)>=0)13result=newRetangulo();14else15result=newTrapezio();1617returnresult;18}1920publicstaticvoidmain(String[]args){21System.out.println(22Eusousabichão!Eusempreseioquetádebaixodebaixodeuma+23variável!\n+24ÉsempreumRetanguloquetáporbaixode+25umavariávelQuadrilátero!26);27for(inti=1;i<=100;i++){28System.out.print(29\tPegandoo+i+"o. Quadrilatero e convertendo para "+30Retangulo:31);32Quadrilateroquad=algumQuadrilateroQualquer();33Retanguloret=(Retangulo)quad;34System.out.println(ret.toString());35}3637System.out.println("EU NÃO DISSE QUE EU SABIA DE TUDO!!!");38}39}4041abstractclassQuadrilatero{42/*blablabla...*/43}44classTrapezioextendsQuadrilatero{45/*blablabla...*/46publicStringtoString(){47return"Sou um Trapezio!";48}49/*blablabla...*/50}51classRetanguloextendsQuadrilatero{52/*blablabla...*/53publicStringtoString(){54return"Sou um Retangulo!";55}56/*blablabla...*/57}
Esse classe de teste serve pra mostrar que nem sempre sabemos qual a classe do objeto que está escondido sob uma variável cujo tipo é uma superclasse da classe do objeto em questão. O método algumQuadrilateroQualquer retorna, de fato, uma referência do tipo Quadrilátero, mas o objeto referenciado por esta referência é definido de forma randômica - A classe [color=blue]RandomBetween[/color] é só pra facilitar a criação de um número randêmico entre dois outros números. Desta forma, não há como prever se lá na linha 32 a variável quad vai estar referenciando um objeto Retangulo ou um objeto Trapezio. Eu rodei esse programa umas dez vezes, e no seu melhor momento, o “programador” conseguiu “acertar” o retângulo apenas 6 vezes… Não tem jeito. Quando na linha 32 quad receber uma referência do tipo Quadrilatero a qual está referenciando um Trapezio, na hora em que você tentar fazer o downcasting da linha 33, o java vai ver que você tá querendo “tratar” o que tá debaixo de quad - um Trapezio - como um Retangulo, e isso vai dar um ClassCastException, posi as classes são incompatíveis.
Como fazer então? Como descobrir qual o tipo do objeto que tá “debaixo” de quad? Utilizando o operador instanceof! Este operador recebe dois operadores: À sua esquerda vai sempre um objeto, e à sua direit vai sempre um nome de classe (definição de classe). Se o objeto operado for uma instância da definição de classe operada, ou se for instância de alguma subclasse(filha, neta, bisneta…) da definição de classe operada, instanceof retorna true. Caso contrário, retorna false.
Mude o main da classe TesteQuadrilatero para este main:
7...8publicclassTesteQuadrilateros{19...20publicstaticvoidmain(String[]args){21System.out.println(22Eunãosousabichão!Vouusaroinstanceofpraverqueméounão+23umretangulo:24);25for(inti=1;i<=10;i++){26System.out.println(27\tPegandoo+i+"o. Quadrilatero e testando para "+28verseéounãoumRetangulo:29);3031Quadrilateroquad=algumQuadrilateroQualquer();32Retanguloret=null;33if(quadinstanceofRetangulo)34ret=(Retangulo)quad;3536if(ret==null)37System.out.println("\t\tNão era um retangulo...");38else39System.out.println("\t\tESSE É UM RETANGULO!!!");40}4142System.out.println("EU NUNCA DISSE QUE EU SABIA DE TUDO...");43}44}4546abstractclassQuadrilatero...
Veja que agora sim estamos fazendo um downcasting responsável a partir da linha 33. Estamos primeiro verificando se o objeto sob a variável quad é Retangulo que esperamos, depois, com base nessa verificação, fazemos o que for necessário.
.
[color=green]Agora, finalmente, vamos ao tal do polimorfismo:[/color]
Todos esses conceitos que te tomaram minutos preciosos da sua atenção e paciência são necessários para entender o polimorfismo. Então, se não entendeu algum, pergunte, ok?
Láááá no comecinho dissemos que…
Olhando o código podemos ver a variável emp assumindo a forma de Comissionado (linha 10) e depois a de Horista (linha 21).
Porque você pode generalizar certas atividades. Imagine que vc queira listar todos os seus funcionários para fazer uma folha de pagamento (O Deitel vai me processar, de verdade! :lol: ). Pra essa tarefa, não importa se um determinado funcionario é horista, comissionado, mensalista, blablaista… não importa! Pra montar uma folha de pagamentos só precisamos do nome, do documento e dos vencimentos a ser pagos para cada empregado, seja ele de que tipo for…
Vamos supor que temos uma base de dados com nossos empregados.
Teremos uma classe chamada [color=blue]EBEmpregados[/color] que terá métodos que simularão a recuperação dos diferentes tipos de empregado. Teremos depois a classe FolhaPagamento, que recuperará todos os empregados e montará a folha de pagamento.
01/**02 * @author Mantu03 */04packagehelp.guj.puppets.polimorfismo.folha;0506importjava.text.NumberFormat;07importjava.util.ArrayList;08importjava.util.List;0910publicclassFolhaPagamento{11List<Empregado>empregados;1213publicFolhaPagamento(){14empregados=newArrayList<Empregado>();15}1617publicStringemitir(){18/*Vamos alimentar a lista de empregados agora. Faremos isso de uma 19 * forma mais detalhada, por motivos didáticos*/2021/*Adicionando os objetos Comissionado à lista de elementos 22 * de tipo Empregado*/23List<Comissionado>comissionados=24DBEmpregados.pegaTodosComissionados();25for(Comissionadocomissionado:comissionados){26empregados.add(comissionado);27}2829/*Adicionando os objetos Horista à lista de elementos 30 * de tipo Empregado*/31List<Horista>horistas=32DBEmpregados.pegaTodosHoristas();33for(Horistahorista:horistas){34empregados.add(horista);35}3637doubletotal=0.0;38NumberFormatnf=NumberFormat.getCurrencyInstance();39StringBuildersb=newStringBuilder(40"NOME\tCPF\tVENCIMENTOS\n"+41"====\t===\t===========\n"42);43for(Empregadoemp:empregados){44sb.append(emp.getNome()+" "+emp.getSobrenome()+"\t");45sb.append(emp.getCpf()+"\t");4647/*Polimorfismo!!!*/48doublevencimentos=emp.vencimentos();4950sb.append(nf.format(vencimentos)+"\n");51total+=vencimentos;52}5354sb.append("-----\nTOTAL: "+nf.format(total));5556returnsb.toString();57}5859publicstaticvoidmain(String[]args){60FolhaPagamentofp=newFolhaPagamento();61System.out.println(fp.emitir());62}63}
Ao executar essa classe, o resultado saíra algo parecido com isso:
Fica meio feio mesmo por que estamos separando com “\t” os campos. Copia e cola no Excel que fica legalzinho! :thumbup:
A nossa classe tem um campo do tipo List chamado empregados, para armazenar os emporegados que irão compor a nossa folha de pagamento.
Na linha 23, obtemos uma lista de elementos de tipo Comissionado chamada comissionados.
Na linha 26, estamos dentro de um laço que itera sobre os elementos de comissionados. Nessa linha, pegamos cada elemento de comissionados e o inserimos na lista empregados. Percebe que neste momento estamos fazendo vários upcastings? A lista empregados “aguarda” elementos do tipo Empregado, e estamos lhe entregando objetos do tipo Comissinado.
O trecho que vai da linha 31 a 35 é análogo. A diferensa é que agora estamos inserindo os horistas na mesma lista empregados, onde já temos inseridos todos os comissionados.
A questão é que, no fundo, no fundo, ambos Comissionado e Horista são-umEmpregado, sacou a jogada? Não estamos adicionando objetos totalmente diferentes…
Na linha 43, é o for onde o polimorfismo se manifesta, mais precisamente na linha 48. Neste momento temos “em mãos” uma variável do tipo Empregado, chamada emp. A partir desta variável, estamos invocando o método vencimentos. Quando o objeto referenciado por emp for um Comissionado, ele vai executar o método vencimentos da classe Comissionado. Quando for um Horista, executará o vencimentos da classe Horista. Isso tudo é feito em tempo de execução! O código já estava compilado antes, mas em tempo de execução o java vai lá e “descobre” qual é a classe do objeto referenciado por emp e executa o método vencimentos apropriado.
Isto, meus amigos, é polimorfismo!
Legal, né? :twisted:
Pra quem chegou (vivo) até aqui, minhas sinceras desculpas pelo post-pergaminho. Espero que tenha ajudado (E que eu não tenha dito nenhuma bobagem no percurso).
Divirtam-se! :shock: :shock: :shock:
A
Adriano_Almeida
Huahuahaua… Sensacional… Pq não coloca isso num tópico da Série: “Se você quer saber mais sobre… Polimorfismo” ?
M
Mantu
Por que não coloco? Simples:
Bikini Cavadão:
Eu sou do povo
Eu sou um Zé Ninguém
…
:lol:
J
josenaldo
PUTZ!
Entrei aqui para ajudar na resposta, mas me vejo obrigado à dar os parabéns aos que responderam!
pafuncio wrote:
Melhor ainda! Coloca num tópico da série “Como responder uma dúvida!”
O
omaisnormalbaba
Ok Mantu…
Mas uma duvida que surgiu…
se acaso eu tiver uma classe Pai com seus atributos e metodos e tbem uma classe Filha com seus atributos e metodos herdados de Pai…Más ae eu queria chamar metodos referente a classe filha que foram declarados por uma interface que somente a classe filha implementou…
Com essa chamada eu nao consigo:
Paiteste=newFilho();teste.metodoDaInterface();
Assim eu nao consigo executar porque pela referencia ela nao contem tal metodo…
Ae vem onde eu queria chegar. Como ela somente executa se for assim:
Filhoteste=newFilho();teste.metodoDaInterface(); // aqui digamos o metodo da interfaceteste.metodoSubscrito();// aqui foi herdado do pai
Esse conceito acima listado foi de Herança e nao de polimorfismo… Correto? Se nao for me avisem…
Eu gostaria de saber como eu faço para executar metodos referentes a um objeto que seja polimorfico (Filho) e que nao esteja declarado na classe Pai.
Assim resolve…
Filhoteste=newFilho();teste.metodoDaInterface();
Obrigado…
L
Link_pg
Olá!
O polimorfismo se aplica somente à métodos que foram declarados na classe pai, pois os métodos (em tempo de compilação) são chamados a partir da REFERÊNCIA.
Se houver um método com o mesmo nome no objeto (no caso na classe filha) então, no caso acima, o método chamado será o do OBJETO (classe filha). Se não houver nenhum método na classe pai com esse nome, o compilador acusará um erro.
Um benefício do polimorfismo: imagine numa empresa onde temos vários funcionários e cada um tem que bater ponto em uma máquina diferente de acordo com seu cargo.
abstractclassFuncionario{publicabstractvoidbaterPonto();}classDiretorextendsFuncionario{publicvoidbaterPonto(){System.out.println("Ponto do diretor");}}classEstagiarioEscravoextendsFuncionario{publicvoidbaterPonto(){System.out.println("Ponto do escravo");}}
Você pode passar QUALQUER classe que extenda Funcionário, ou seja, se na empresa resolverem contratar elefantes, é só criar uma classe Elefante extends Funcionario, pois assim a classe Elefante herdará (e será obrigada a implementar) o método baterPonto() da classe Funcionario. Desse jeito podemos ver que qualquer classe que extenda Funcionario terá obrigatoriamente o método baterPonto().
Se você chamar o método assim:
baterPonto(newDiretor());
A saída será: “Ponto do diretor”
Se você chamar o método assim:
baterPonto(newEstagiarioEscravo());
A saída será: “Ponto do escravo”
Na hora de chamar o método é que (em tempo de execução) será decidido QUAL método chamar a partir do tipo do objeto que está chamando o método.
Espero ter tirado sua dúvida e/ou acrescentado algum conhecimento.
Abraços
E
evandroshx
Ae mantu, lembro de ti da época da federal hein cara.
Explicação show de bola meu velho.
W
WillyKocher
respondendo sua ultima duvida, se voce deseja executar um metodo da classe filho que não exista na classe pai (API ) , utilizando uma referencia do tipo classe pai:
Pai variavel1 = new Filho ();
voce so pode fazer isto atraves de um downcasting, ou seja voce precisa ter uma vairavel que seja do mesmo tipo do objeto que possui o metodo que voce quer executar( classe filho )
Filho variavel2 = (Filho) variavel1 ;
claro se quizer chamar sem declaração de uma nova referncia tambem pode chamar o metodo assim:
( (Filho) variavel1 ) .metodo();
se o pai nao sabe oque o filho dele faz dentro do banheiro trancado nao tem jeito so o filho pode fazer.
bom se quizer uma recomendação da uma lida no capitulo 2 do livro da kathy sierra, ta bem explicado isto lá
O
omaisnormalbaba
Valeu galera…
E
ECO2004
Eu tenho uma dúvida:
classC1{publicvoidmostraDados(){System.out.print(" 1 ");}}classC2extendsC1{publicvoidmostraDados(){System.out.print(" 2 ");}}publicclassProg{publicstaticvoidf(C1c){System.out.print(" A ");c.mostraDados();}publicstaticvoidf(C2c){System.out.print(" B ");c.mostraDados();}publicstaticvoidmain(Stringargs[]){C1c1=newC2();f(c1);}}
Por que na “main”, quando faço
“C1 c1 = new C2();
f(c1);”
ele invoca a função f(C1 c), ao invés de f(C2 c)?
Quando faço C1 c1 = new C2(), c1 não se torna C2?
M
M3g4d3th
Nossa velho, o cara deu uma aula de Polimorfismo. Valeu.
V
ViniGodoy
Não, ele “não se torna nada”. A resolução de qual método deve ser chamado não tem nada a ver com polimorfismo ou com o tipo em runtime. Ele olha para o tipo estático.
Entretanto isso que você fez é completamente errado.
Se você usasse uma variável com o tipo C2, nada garantiria também que ele iria chamar o método f(C2), já que C2 também é um C1.
M
M3g4d3th
Não, ele “não se torna nada”. A resolução de qual método deve ser chamado não tem nada a ver com polimorfismo ou com o tipo em runtime. Ele olha para o tipo estático.
Entretanto isso que você fez é completamente errado.
Se você usasse uma variável com o tipo C2, nada garantiria também que ele iria chamar o método f(C2), já que C2 também é um C1.
Ae cara, não saquei o que tu quis dizer, tem como explicar de uma forma melhor?
Abraço.
V
ViniGodoy
Considere as classes Cachorro, que é filho de animal.
Um método:
voidfazQualquerCoisa(Animala);
Pode ser chamado assim:
fazQualquerCoisa(newCachorro());
Isso pq Cachorro é um Animal. Porém, como resolver a ambiguidade, caso existam 2 métodos sobrecarregados assim:
voidfazQualquerCoisa(Animala);
voidfazQualquerCoisa(Cachorroa);
Tanto um, quanto o outro método, admitem o uso de um cachorro. O bom senso diz que o Java deveria chamar o método mais específico, porém, o Java não dá essa garantia. É um dos poucos pontos obscuros da linguagem. O método que será chamado depende de qual foi carregado primeiro, e isso pode variar até mesmo de execução para execução.
Quanto à duvida do colega. Para resolução de métodos, olha-se o tipo da referência, e não do valor que ela contém. Uma variável criada assim:
Animala=newCachorro();
Só poderá ser usada em métodos que recebam o tipo Animal como parâmetro, ou supertipos de Animal. Para chamar num método que aceite um Cachorro é necessário fazer cast.
M
M3g4d3th
ViniGodoy:
Considere as classes Cachorro, que é filho de animal.
Um método:
voidfazQualquerCoisa(Animala);
Pode ser chamado assim:
fazQualquerCoisa(newCachorro());
Isso pq Cachorro é um Animal. Porém, como resolver a ambiguidade, caso existam 2 métodos sobrecarregados assim:
voidfazQualquerCoisa(Animala);
voidfazQualquerCoisa(Cachorroa);
Tanto um, quanto o outro método, admitem o uso de um cachorro. O bom senso diz que o Java deveria chamar o método mais específico, porém, o Java não dá essa garantia. É um dos poucos pontos obscuros da linguagem. O método que será chamado depende de qual foi carregado primeiro, e isso pode variar até mesmo de execução para execução.
Quanto à duvida do colega. Para resolução de métodos, olha-se o tipo da referência, e não do valor que ela contém. Uma variável criada assim:
Animala=newCachorro();
Só poderá ser usada em métodos que recebam o tipo Animal como parâmetro, ou supertipos de Animal. Para chamar num método que aceite um Cachorro é necessário fazer cast.
Acho que saquei… Li umas 3x e entendi que tem que ser mais específico. Mas mesmo se você não for específico também funciona correto?
Abraço.
V
ViniGodoy
O que tem que ser mais específico?
R
ralphsilver
Nossa! Depois da resposta do nosso amigo Mantu porque ainda não mudaram o título para resolvido?
M
ManoJava
Pra quem chegou (vivo) até aqui, minhas sinceras desculpas pelo post-pergaminho. Espero que tenha ajudado (E que eu não tenha dito nenhuma bobagem no percurso).
Divirtam-se! :shock: :shock: :shock:
Sinceramente seu post motiva ler até o final, pois não seria muito inteligente não terminar de ler a explicação. Parbéns
Att.
V
ViniGodoy
Pq em 2007 não havia ainda essa prática no fórum.
E
ECO2004
“Para resolução de métodos, olha-se o tipo da referência, e não do valor que ela contém…”
O que você quis dizer com isso?
Animal a = new Cachorro();
A variável “a” está referenciando “Cachorro”, correto?
Outra coisa, tem como você ser mais claro a respeito de tempo de execução (runtime) a a parte “estática” comentada?
Vlw
V
ViniGodoy
ECO2004:
“Para resolução de métodos, olha-se o tipo da referência, e não do valor que ela contém…”
O que você quis dizer com isso?
Animal a = new Cachorro();
A variável “a” está referenciando “Cachorro”, correto?
Outra coisa, tem como você ser mais claro a respeito de tempo de execução (runtime) a a parte “estática” comentada?
Vlw
Sim está referenciando um cachorro. Mas o tipo da variável de referência a é Animal, e não cachorro. Na hora de escolher que método chamar, é sobre esse tipo que ele vai olhar, até porque, ele não tem como garantir que lá dentro haverá sempre um cachorro. Veja bem, no caso onde a chamada e a inicialização da variável estão próximos, é fácil vermos que Animal contém um cachorro. Mas lembre-se que você pode ter uma criação assim:
Animala=carregarAnimal();
E nesse caso seria muito trabalhoso (para não dizer impossível) determinar o tipo do animal.
E
ECO2004
Eu entendi…
É por isso que usamos obj instanceof Classe, para sabermos se tal objeto pertence à classe.
Me corrija se eu estiver errado, mas quando faço “Animal a = new Cachorro();”, isso somente ocorre em tempo de execução, até porque o new aloca memória e somente é feito isso em tempo de execução. Na compilação, não há memória alocada e tudo que a linguagem sabe é que “a” é do tipo Animal.
Esse também é um dos motivos pela qual o downcasting necessita de:
Cachorro c = (Cachorro)a;
pois “c” não sabe quem está “embaixo” de “a.”
No meu exemplo anterior, criticado por você por ser errado, a função chamada é a f(C1 c) por quê???
E
ECO2004
É por que f(c1) não sabe que ocorreu “C1 c1 = new C2();” ?
Para que chamasse f(C2 c) ao invés de f(C1 c), teria que fazer na “main” f((C2)c1), pois c1, na instrução “f(c1)” não tem como ler a instrução anterior e ver que houve referência à C2?