Polimorfismo

Ae mantu, lembro de ti da época da federal hein cara.

Explicação show de bola meu velho.

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á :wink:

Valeu galera…

Eu tenho uma dúvida:

class C1 
{
	public void mostraDados() 
	{
		System.out.print(" 1 ");
	}
}
class C2 extends C1 
{
	public void mostraDados() 
	{
		System.out.print(" 2 ");
	}
}

public class Prog 
{
	public static void f(C1 c) 
	{
		System.out.print(" A ");
		c.mostraDados();
	}
	
	public static void f(C2 c) 
	{
		System.out.print(" B ");
		c.mostraDados();
	}
	
	public static void main(String args[]) 
	{
		C1 c1 = new C2();
		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?

Nossa velho, o cara deu uma aula de Polimorfismo. Valeu.

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.

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.[/quote]

Ae cara, não saquei o que tu quis dizer, tem como explicar de uma forma melhor?

Abraço.

Considere as classes Cachorro, que é filho de animal.

Um método:

void fazQualquerCoisa(Animal a);

Pode ser chamado assim:

fazQualquerCoisa(new Cachorro());

Isso pq Cachorro é um Animal. Porém, como resolver a ambiguidade, caso existam 2 métodos sobrecarregados assim:

void fazQualquerCoisa(Animal a);
void fazQualquerCoisa(Cachorro a);

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:

Animal a = new Cachorro();

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.

[quote=ViniGodoy]Considere as classes Cachorro, que é filho de animal.

Um método:

void fazQualquerCoisa(Animal a);

Pode ser chamado assim:

fazQualquerCoisa(new Cachorro());

Isso pq Cachorro é um Animal. Porém, como resolver a ambiguidade, caso existam 2 métodos sobrecarregados assim:

void fazQualquerCoisa(Animal a);
void fazQualquerCoisa(Cachorro a);

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:

Animal a = new Cachorro();

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.
[/quote]

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.

O que tem que ser mais específico?

Nossa! Depois da resposta do nosso amigo Mantu porque ainda não mudaram o título para resolvido?

[quote]
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: [/quote]

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.

Pq em 2007 não havia ainda essa prática no fórum.

“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

[quote=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[/quote]

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:

Animal a = carregarAnimal();

E nesse caso seria muito trabalhoso (para não dizer impossível) determinar o tipo do animal.

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

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

Isso mesmo.

Obrigado!