Polimorfismo

17 respostas
shenn

Ontem na faculdade o professor estava explicando polimorfismo, ai surgiu uma duvida, e ao perguntar pra ele, ele me disse assim:

  • Ele perde a referencia.

Perde referencia do que?

Segue meu codigo com minha duvida.

public class Principal {

	public static void main(String[] args) {
		Animal animal = new Cachorro();
		
		animal.comer();
		
		animal.latir(); // porque eu não consigo acessar o metodo latir? 
		
	}
public class Cachorro extends Animal{

	public void latir(){
		System.out.println("O Cachorro esta latindo");
	}
	
}
public class Animal {

	public void comer (){
		System.out.println("O animal está comendo");
	}
	
}

17 Respostas

S

porque você executou o animal.comer() irá abrir seu metodo, dentro do metodo animal.comer() so apresenta a mensagem nada mas, assim perdeu a referencia com a classe principal

shenn

eu sei que disso, mas pq ele não permite eu executar o

animal.latir();
nel

shenn:
Ontem na faculdade o professor estava explicando polimorfismo, ai surgiu uma duvida, e ao perguntar pra ele, ele me disse assim:

  • Ele perde a referencia.

Perde referencia do que?

Segue meu codigo com minha duvida.

public class Principal {

	public static void main(String[] args) {
		Animal animal = new Cachorro();
		
		animal.comer();
		
		animal.latir(); // porque eu não consigo acessar o metodo latir? 
		
	}
public class Cachorro extends Animal{

	public void latir(){
		System.out.println("O Cachorro esta latindo");
	}
	
}
public class Animal {

	public void comer (){
		System.out.println("O animal está comendo");
	}
	
}

Shenn, cavalo late ? :slight_smile:
Se sim, vou ficar impressionado . O que eu quero dizer ? Todo animal (eu acho) come, mas todo animal late ? Não.
Por isso na classe Animal não contém o método latir. O método latir é especifico da classe Cachorro, entende ? :slight_smile:

rmendes08

Isso acontece porque o Java usa o tipo da referência para saber quais métodos podem ser chamados sobre um objeto, enquanto que o tipo do objeto em si é usado para determinar qual versão do método será executado. Um acontece em tempo de compilação e o outro em tempo de execução. Isso acontece porque na prática, em tempo de compilação não é possível determinar qual é o tipo real do objeto, o compilador conhece apenas o tipo da variável de referência. Por exemplo, no método abaixo:

public void foo(Animal animal){
   animal.comer();
   //...
}

não há como saber qual é o tipo real do objeto, você sabe apenas que está recebendo um animal, se é um Gato, Cachorro, Canguru … isso não te interessa.

shenn

então é tipo assim? O meu objeto animal vai receber um cachorro..

ai o java não consegue "saber" qual tipo de animal ele esta recebendo?

por isso eu nao consigo fazer
animal.latir();
nel
shenn:
então é tipo assim? O meu objeto animal vai receber um cachorro..

ai o java não consegue "saber" qual tipo de animal ele esta recebendo?

por isso eu nao consigo fazer
animal.latir();

Como o mendes explicou, ele tem a referência a classe Animal, não a implementação dela.
Todos os métodos que não estejam na classe "Pai" não será reconhecidas por ela. Um filho sabe todos os métodos (considere tudo publico) que o seu Pai possui, por isso consegue usa-los. Todavia, o Pai só conhece seus próprios métodos, como o filho os implementou e se possui mais métodos ou não, não interessa a ele. A referência permanece sendo para a classe Pai, no seu caso, Animal.

Se quiser usar o método latir, você faz um cast direto, o que perde o sentido do polimorfismo nesse caso, ou simplesmente instancia diretamente a classe Cachorro, ai sim, ele tem a referência para o Cachorro e vai conhecer todos os seus métodos, assim como de seu Pai (Animal).

denisspitfire

ou seja…

public class Teste {

	public static void main(String[] args) {
		Cachorro dog = new Cachorro();

		dog.comer();
		dog.latir();

	}

}

class Cachorro extends Animal {
	public void latir() {
		System.out.println(" O Animal esta Latindo");
	}
}

abstract class Animal {
	public void comer() {
		System.out.println(" O Animal esta Comendo ");
	}
}

Podemos colocar a classe Animal como abstrata pois ela nao pode ser instanciada somente extendida… para nao dar esses problemas.
Classes mais “altas” nao sao instanciadas para ja ter uma certa segurança de qual metodo voce quer.

shenn

ahaa então seria tipo assim:

o objeto pai esta “recebendo” um objeto filho, por isso eu não consigo acessar os métodos do objeto filho…

Mas porque eu iria fazer

Animal animal = new Cachorro();

sendo que eu nao tenho como acessar os metodos da classe cachorro?

rmendes08

shenn:
ahaa então seria tipo assim:

o objeto pai esta “recebendo” um objeto filho, por isso eu não consigo acessar os métodos do objeto filho…

Mas porque eu iria fazer

Animal animal = new Cachorro();

sendo que eu nao tenho como acessar os metodos da classe cachorro?

Simplesmente porque não lhe interessa. Geralmente, quando você usa uma variável cujo tipo é uma superclasse, você não escolhe qual implementação você vai usar. Pode parecer inútil agora, mas você vai ver uma coisa chamada baixo acoplamento, que permite modularizar melhor seus programas.

[/quote]

denisspitfire

voce esta falando que esta recebendo um animal… mas animal pode ser cachorro, gato… sei la qualquer animal

voce quer comprar um animal…

dai voce espera oque quanto voce falar pro animal latir?
voce espera ele emitir um som…

porem um coelho é um animal e nao late.

oque é mais alto nivel, por questao de segurança e detalhamento voce nao pode instanciar… só extender.

shenn

ahaa deu pra entender mais ou menos… =D

porem ainda é um pouco complicado

vlw galera pelas dicaas :smiley:

carloshsamaral

Amigo eu estava com a mesma dúvida e me indicaram esse link aqui.

Com ele consegui entender oque vem a ser Polimorfismo !

shenn

bom site =D

T

rmendes08:
Isso acontece porque o Java usa o tipo da referência para saber quais métodos podem ser chamados sobre um objeto, enquanto que o tipo do objeto em si é usado para determinar qual versão do método será executado. Um acontece em tempo de compilação e o outro em tempo de execução. Isso acontece porque na prática, em tempo de compilação não é possível determinar qual é o tipo real do objeto, o compilador conhece apenas o tipo da variável de referência. Por exemplo, no método abaixo:

public void foo(Animal animal){
   animal.comer();
   //...
}

não há como saber qual é o tipo real do objeto, você sabe apenas que está recebendo um animal, se é um Gato, Cachorro, Canguru … isso não te interessa.

Então cara, eu saquei essa de que na compilação ele não liga pra diferença dos tipos mas na execução sim.

O unico problema restante é:
Digamos que na classe Cachorro tenho o atributo corDoPelo. E na main eu faça o seguinte:

//...
Cachorro an1 = new Cachorro();
an1.setCodDoPelo("Preta");
Animal an2 = an1;      //Se nessa linha não da erro...
an2.latir();                 //Por que nessa dá?

Até onde eu consegui entender de variaveis de referencia, elas não guardam o conteúdo em si, guardam apenas uma referencia para a memoria.
Aí eu fiquei na duvida… como an2 pode aceitar a mesma referencia de an1, mesmo perdendo o valor da cor?? Oq acontece?
E também, porque ele não encontra o metodo latir se ele está com a mesma referencia que an1???

(Mals por estar ressuscitando o topico dps de tanto tempo xD)

sergiotaborda

shenn:
Ontem na faculdade o professor estava explicando polimorfismo, ai surgiu uma duvida, e ao perguntar pra ele, ele me disse assim:

  • Ele perde a referencia.

Perde referencia do que?

Perde referencia de coisa nenhuma…

Vc definiu a veriável como sendo do tipo Animal. Objetos do tipo “Animal” não têm o método “latir” porque apenas objetos do tipo Cachorro o têm.

A variável é polimorfica no sentido que ela aceita qualquer objeto que seja um animal, mas apenas os métodos que “Animal” tem é que podem ser chamados. Como Cachorro é um Animal ele tem o método comer. Então tudo bem. Mas “Animal” não tem o método latir, logo dá erro de compilação. Simples.

Vc eve tar pensando que “mas o objeto verdadeiro é um Cachorro”. Sim, mas vc só está enxergando a parte "Animal’ dele. Se vc quiser enxergar o resto vc tem que usar a variável como sendo do tipo Cachorro ( ou usar cast, ou usar interfaces, mas isso é uma aula mais avançada).

Ou seja, a chamada é transferida ao objeto correto, mas vc pode usar as chamadas que o tipo da variável tem.

T

Então… a ideia em si eu já entendi de boa… o estranho é o comportamento da linguagem em si q eu qria saber mais…
Mas já deu pra esclarecer sim!
Valeu!

sergiotaborda

As variáveis em java não contém apenas a referencia aos objetos ( veja que a referencia não é um endereço de memoria (isso seria um ponteiro) é um numero mais um numero num mapa/tabela )
Eles contém tb o tipo. Por isso se diz que java é fortemente tipado.

A variável do tipo Animal e a variável do tipo Cachoro são diferentes. Quando a referencia é a mesma, o objeto final na ponta das chamadas cai no mesmo objeto. Mas é o tipo da variável que permite ao compilador saber que método estão disponíveis para aquele tipo. Ao chamar animal.latir, a variável de animal, o compilador vê se existe esse metodo em “animal”, não existe. Logo, dá erro. É muito simples. Não têm que ver com herança. Use uma variável String e chame latir() vai dar o mesmo erro, porque string não tem o método latir. O compilador só faz esta analise simples porque ele não tem a referencia, isso só em runtime que vai existir. Então ele não tem como precorrer a referencia e ver que naquela variável existe um cachorro.

A regra é : só pode chamar método que existem no tipo da variável. Simples assim.

Criado 26 de abril de 2012
Ultima resposta 15 de fev. de 2013
Respostas 17
Participantes 8