Polimorfismo

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 é.

                      Animal              classe pai
                     ---------
                     +peso
                     +tamanho
                     +idade
                    ------------
                     +alimentar()

   Animal::Mamifero                    Animal::ave
   -------------------                 ---------------
   ------------------                   - tamanho do ovo
   +alimentar()                       --------------    
   +amamentar()                      +chocar()

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…???

Dá uma lida aqui:
http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming

Olha só a beleza do método alimentar();
:smiley:

Cara,

Uma apostila que explica mto bem OO é a da Caelum: http://www.caelum.com.br/caelum/apostila/caelum-java-objetos-fj11.pdf

sim… polimorfismo: quando se reescreve um método implementado na classe Pai.

Ãhn??? Isso se chama Override.

Polimorfismo em suma é referenciar uma classe derivada como se fosse a classe pai!

o interessante de polimorfismo é voce saber que toda ave e mamifero é um animal… entao na hora de instaciar essas classes voce deve fazer assim:

Animal cachorro = new Mamifero();

voce naum levaria em conta o polimorfismo se voce fizesse assim:

Mamifero cachorro = new Mamifero();

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!!

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:

                                      cavalo
                                    ----------
                                     +preto
                                     +mangalarga
                                    ------------
                                     + corre()
                                     + come()


              burro
              ---------
              +branco
              +sem pelo
             --------------
              +come()
              + carrega carroça

dai quando eu for instancia a classe burro e soh eu fazer dessa forma

      burro chama = new cavalo é isso????
 uma dúvida que eu tenho se caso a classe burro não tivesse em comun 
 o procedimentoi come() ai dar na mesma..????

então puppets

na sua logica burro herda cavalo ??/

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!

valew cara ajudou bastante

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!!

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

Ãhn??? Isso se chama Override.

Polimorfismo em suma é referenciar uma classe derivada como se fosse a classe pai![/quote]

nohhh cara… viajei msm… o trem ta feio msm… kkkk…
vlw por me corrigir… :oops:

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:[quote=camilolopes]ai temos polimorfismo… muitas formas…[/quote]

acho que é isso, tomara q eu não tenha complicado tudo…

simsim!! vlw por complementar

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:

package help.guj.puppets.polimorfismo.folha;

public class Teste1 {

	public static void main(String[] args) {
		Horista horista = new Horista();
		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 É-UM empregado. 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:

Empregado zequinha = new Empregado();

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

public abstract double vencimentos();

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:

public abstract class Foo{
	public void bar(){
		System.out.println("bar");
	}
}

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*/ class Empregado{...

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ê… :wink:
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:

Empregado emp = new Comissionado();

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:

Quadrilatero quad = new Retangulo();

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:

Retangulo ret = quad;

Isso simplesmente não vai compilar.

Opa! Alto lá! Nós quem, cara-pálida? Um humano que lê o seu código

Quadrilatero quad = new Retangulo();
Retangulo ret = quad;

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:

Quadrilatero quad = new Retangulo();
Retangulo ret = (Retangulo)quad;

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 Mantu
3	 */
4	package help.guj.puppets.polimorfismo.simples;
5
6	import br.com.autbank.tech.util.math.RandomBetween;
7
8	public class TesteQuadrilateros {
9		public static Quadrilatero algumQuadrilateroQualquer() {
10			Quadrilatero result;
11
12			if(RandomBetween.getInt(-100, 100) >= 0)
13				result = new Retangulo();
14			else
15				result = new Trapezio();
16
17			return result;
18		}
19
20		public static void main(String[] args) {
21			System.out.println(
22				Eu sou sabichão! Eu sempre sei o que tá debaixo debaixo de uma  +
23				variável!\n +
24				É sempre um Retangulo que tá por baixo de  +
25				uma variável Quadrilátero!
26			);
27			for (int i = 1; i <= 100; i++) {
28				System.out.print(
29					\tPegando o  + i + "o. Quadrilatero e convertendo para " +
30					Retangulo: 
31				);
32				Quadrilatero quad = algumQuadrilateroQualquer();
33				Retangulo ret = (Retangulo)quad;
34				System.out.println(ret.toString());
35			}
36
37			System.out.println("EU NÃO DISSE QUE EU SABIA DE TUDO!!!");
38		}
39	}
40
41	abstract class Quadrilatero{
42		/*blablabla...*/
43	}
44	class Trapezio extends Quadrilatero{
45		/*blablabla...*/
46		public String toString() {
47			return "Sou um Trapezio!";
48		}
49		/*blablabla...*/
50	}
51	class Retangulo extends Quadrilatero{
52		/*blablabla...*/
53		public String toString() {
54			return "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	...
8	public class TesteQuadrilateros {
19		...
20		public static void main(String[] args) {
21			System.out.println(
22				Eu não sou sabichão! Vou usar o instanceof pra ver quem é ou não  +
23				um retangulo:
24			);
25			for (int i = 1; i <= 10; i++) {
26				System.out.println(
27					\tPegando o  + i + "o. Quadrilatero e testando para " +
28					 ver se é ou não um Retangulo: 
29				);
30
31				Quadrilatero quad = algumQuadrilateroQualquer();
32				Retangulo ret = null;
33				if(quad instanceof Retangulo)
34					ret = (Retangulo)quad;
35
36				if(ret == null)
37					System.out.println("\t\tNão era um retangulo...");
38				else
39					System.out.println("\t\tESSE É UM RETANGULO!!!");
40			}
41
42			System.out.println("EU NUNCA DISSE QUE EU SABIA DE TUDO...");
43		}
44	}
45
46	abstract class Quadrilatero...

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…

O que diabos isso quer dizer?
O polimorfismo se manifesta quando temos, voltando ao caso dos empregados , uma variável emp do tipo Empregado que referencia, por exemplo, um objeto do tipo Comissionado, e então invocamos a partir de emp um método presente em Empregado e ao mesmo tempo sobrescrito em Comissionado - o toString, por exemplo. Empora a variável emp, que está invocando o toString, seja do tipo Empregado, o método toString que o java vai executar não é aquele escrito na classe Empregado… O polimorfismo “faz com que” o Java verifique:
:arrow: Qual é a classe do objeto referenciado por emp? (Comissionado)
:arrow: Essa classe tem um método toString com a mesma assinatura daquele invocado a partir de emp? (Sim! Tem sim!)
:arrow: Se tem, então execute o toString da classe do objeto ao invés do toString da classe da variável emp. (Vai executar o toString de Comissionado ao invéz do toString de Empregado.
Situação análoga ocorreria com o método vencimentos.
Note que neste momento, a variável emp é um Empregado que age como se fosse um Comissionado. Se por acaso atribuírmos à mesma variável emp um outro objeto, desta vez um do tipo Horista e invocarmos “emp.toString()”, a variável emp, que é do tipo Empregado, que agora há pouco se comportou como um Comissionado, agora se comportará como (assumirá a forma de, se morfará em) um Horista.
Colocando isso em linhas de código, seria algo assim:

01 /**
02  * @author Mantu
03  */
04 package help.guj.puppets.polimorfismo.folha;
05 
06 public class TesteSimples {
07   public static void main(String[] args) {
08     Empregado emp;
09     
10     emp = new Comissionado(
11       "Luciano",
12       "Mantuaneli",
13       "123.456.789-00",
14       100.0,
15       8525.88,
16       0.15
17     );
18     System.out.println(emp.toString());
19     System.out.println();
20     
21     emp = new Horista(
22       "Gustav",
23       "Mahler",
24       "123.456.789-00",
25       52.74,
26       160.0
27     );
28     System.out.println(emp.toString());
29   }
30 }

A saída deste programinha é a seguinte:

Nome: Luciano Mantuaneli
CPF: 123.456.789-00
Salário Base: R$ 100,00
Total de Vendas: R$ 8.525,88
Taxa Comissao: 15%
Vencimentos no período: R$ 1.378,88

Nome: Gustav Mahler
CPF: 123.456.789-00
Salário/Hora: R$ 52,74
Horas trabalhadas: 160.0
Vencimentos no período: R$ 8.438,40

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 Mantu
03  */
04 package help.guj.puppets.polimorfismo.folha;
05 
06 import java.text.NumberFormat;
07 import java.util.ArrayList;
08 import java.util.List;
09 
10 public class FolhaPagamento {
11   List<Empregado> empregados;
12   
13   public FolhaPagamento() {
14     empregados = new ArrayList<Empregado>();
15   }
16   
17   public String emitir() {
18     /*Vamos alimentar a lista de empregados agora. Faremos isso de uma 
19      * forma mais detalhada, por motivos didáticos*/
20     
21     /*Adicionando os objetos Comissionado à lista de elementos 
22      * de tipo Empregado*/
23     List<Comissionado> comissionados = 
24       DBEmpregados.pegaTodosComissionados();
25     for (Comissionado comissionado : comissionados) {
26       empregados.add(comissionado);
27     }
28     
29     /*Adicionando os objetos Horista à lista de elementos 
30      * de tipo Empregado*/
31     List<Horista> horistas = 
32       DBEmpregados.pegaTodosHoristas();
33     for (Horista horista : horistas) {
34       empregados.add(horista);
35     }
36     
37     double total = 0.0;
38     NumberFormat nf = NumberFormat.getCurrencyInstance();
39     StringBuilder sb = new StringBuilder(
40       "NOME\tCPF\tVENCIMENTOS\n" +
41       "====\t===\t===========\n"
42     );
43     for (Empregado emp : empregados) {
44       sb.append(emp.getNome() + " " + emp.getSobrenome() + "\t");
45       sb.append(emp.getCpf() + "\t");
46       
47                             /*Polimorfismo!!!*/
48       double vencimentos = emp.vencimentos();
49       
50       sb.append(nf.format(vencimentos) + "\n");
51       total += vencimentos;
52     }
53     
54     sb.append("-----\nTOTAL: " + nf.format(total));
55     
56     return sb.toString();
57   }
58   
59   public static void main(String[] args) {
60     FolhaPagamento fp = new FolhaPagamento();
61     System.out.println(fp.emitir());
62   }
63 }

Ao executar essa classe, o resultado saíra algo parecido com isso:

NOME	CPF	VENCIMENTOS
====	===	===========
Luciano Mantuaneli	291.785.125-08	R$ 526,29
Hector Berlioz	749.954.326-83	R$ 551,22
Antonin Dvorak	291.090.533-11	R$ 1.669,05
Piotr Yilich Tchaikoviski	204.875.382-12	R$ 1.404,87
Gustav Mahler	361.950.985-84	R$ 8.438,40
Ludwig Van Beethoven	578.428.744-16	R$ 14.404,00
Johannes Brahms	437.569.706-58	R$ 3.222,00
Mozart Camargo-Guarnieri	744.392.996-65	R$ 14.800,00
Heitor Villa-Lobos	063.055.887-83	R$ 15.050,20
-----
TOTAL: R$ 60.066,03

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-um Empregado, sacou a jogada? :wink: 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:

Huahuahaua… Sensacional… Pq não coloca isso num tópico da Série: “Se você quer saber mais sobre… Polimorfismo” ?

Por que não coloco? Simples:

[quote=Bikini Cavadão]
Eu sou do povo
Eu sou um Zé Ninguém
…[/quote]
:lol:

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!”

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:

Pai teste = new Filho();
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:

Filho teste = new Filho();
teste.metodoDaInterface(); // aqui digamos o metodo da interface
teste.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…

Filho teste = new Filho();
teste.metodoDaInterface();

Obrigado…

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.

Ex:

Pai teste = new Filho();
teste.algumMetodoDaClassePai();

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.

abstract class Funcionario{
    public abstract void baterPonto();
}

class Diretor extends Funcionario{
    public void baterPonto(){
        System.out.println("Ponto do diretor");
    }
}

class EstagiarioEscravo extends Funcionario{
    public void baterPonto(){
        System.out.println("Ponto do escravo");
    }
}

Daí no sistema principal temos…

...
public void baterPonto(Funcionario f){
    f.baterPonto();
}

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(new Diretor());

A saída será: “Ponto do diretor”

Se você chamar o método assim:

baterPonto(new EstagiarioEscravo());

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