quarta-feira, 9 de setembro de 2009

Polimorfismo,cast Objetos,instanceof

Sumário: Polimorfismo,Sobrescrita e Polimorfismo,Argumentos e Polimorfismo,cast de Objetos,instanceof

Objetos tem apenas uma forma aquela que lhe é dada quando ele é construído porem uma variável é polimórfica ou seja ela faz referência para diferentes objetos.
Relembrando:



Como se declara uma variável de referência?





Clique na imagem para ampliar



Quando eu crio um objeto oque realmente acontece?


Acontece a subida no topo da hierarquia do objeto, obtendo - se um objeto que tem tanto membros(Métodos, Atributos) próprios quanto de todas as SuperClass da Hierarquia.
Vejamos:





Clique na imagem para ampliar
, Lembrando que Implicitamente escrito ou explicitamente Toda Classe que não tenha um SuperClasse explicitamente escrito tem java.lang.object Implicitamente ou Explicitamente escrito como SuperClasse.


Sabemos que se criarmos um objeto do tipo
Chefe, ele terá todos os membros(Métodos e Atributos que todas as Hierarquias acima).


Vejamos:




new Chefe();



Vamos obter isso:





Clique na imagem para ampliar
Ja deu para perceber que todo objeto Chefe tem:
Tudo que é de direito ao cargo, no caso
carroEmpresa
Chefe também
tem tudo que encarregado tem no caso bonusSalarial e supervisionar()
Chefe também
tem tudo que Funcionário tem no caso nome, salario e trabalhar()
Chefe também
tem tudo que java.lang.Object tem Sendo assim vou abreviar para ficar mais facil o entendimento:








Outro exemplo:



Se Criar-mos um objeto Funcionario, Resumidamente teremos:


Lembre-se que todo funcionário tem:

Oque é de direito ao cargo dele no caso : nome, salario e trabalhar()

E todo objeto Funcionário tem tudo que java.lang.Object tem




Relação variável de referência e Objeto:


É aqui realmente que se encontra o Polimorfismo, de acordo com a palavra em si:
Polimorfismo = Muitas formas

De acordo com a variável de referência você poderá acessar somente OQUE FAZ PARTE DAQUELE TIPO DE OBJETO VEJAMOS:

Como Chefe é um Encarregado, ou seja é uma SubClasse da Classe Encarregado, Então isso é possível:




Clique na imagem para ampliar





Oque acabamos de fazer?


Aqui temos um objeto do tipo Chefe porem a variável aponta para o objeto do tipo Encarregado, OU SEJA ela somente pode usar tudo que um Encarregado tem...
Um chefe é um Encarregado
Porem um Encarregado não é um chefe

Vejamos:



Clique na imagem para ampliar
Se você tentar acessar:

identificador.carroEmpresa = true; Dará Erro de Compilação, Pois A variável de referência é do tipo Encarregado, E ENCARREGADO não tem carro da Empresa.

Se você tentar acessar:

identificador.trabalhar(); Compilará Normalmente, Pois o método trabalhar é de Funcionário e a variavel de referência Aponta para o Encarregado do Objeto, e Encarregado é um Funcionário.

Por isso chegamos a conclusão de:
Um objeto só tem uma forma porem a variável de referência pode apontar para qualquer forma dele.


Sobrescrita e Polimorfismo:

Muita atenção em Sobrescrita e Polimorfismo,

Vejamos o exemplo:

public class Funcionario{

public void metodo(){
System.out.println("Funcionario");

}

}

public class Gerente extends Funcionario{

public void metodo(){
System.out.println("Gerente");

}


}


public class TestClass{

public static void main(String array [ ]){

Funcionario funcionario = new Funcionario();
funcionario.metodo();


Gerente gerente = new Gerente();
gerente.metodo();



}

}




Clique na imagem para ampliar




Em
funcionario.metodo(); Aparecerá:
Funcionario


Em
gerente.metodo(); Aparecerá:
Gerente

Podemos ver dessa forma também:




Clique na imagem para ampliar





Porem isso não acontece aqui:


Temos uma diferença seria quando existe Sobrescrita de método e Polimorfismo


public class Funcionario{

public void metodo(){
System.out.println("Funcionario");

}

}

public class Gerente extends Funcionario{

public void metodo(){
System.out.println("Gerente");

}


}

public class TestClass{

public static void main(String array [ ]){

Funcionario funcionario = new Gerente();
funcionario.metodo();




}

}


Neste exemplo oque teremos na saída Padrão é:

Gerente

POR CAUSA DA SOBRESCRITA QUE ISSO ACONTECE

Em métodos sobrescritos na verdade obtém-se o comportamente associado ao objeto em tempo de EXECUÇÃO ou seja, invocamos o método do objeto gerente cujo sobrescreve o método da SuperClasse dele ou seja Funcionario.

PORTANTO CUIDADO COM INVOCAÇÃO DE MÉTODOS SOBRESCRITOS.



Argumentos e Polimorfismo:


Você pode ter um Argumento de um tipo que seja uma SuperClasse e pode receber qualquer parâmetro que seja uma SubClasse dessa SuperClasse que esta como argumento.

Vejamos:




Clique na imagem para ampliar


Vejamos em sintax java:



public class Funcionario{

public void
metodo(Object argumento){

}


}


public class
Encarregado extends Funcionario{

}


public class
Chefe extends Encarregado{

}


public class
ClassTest{


public static void main(String array[ ]){


Chefe chefe = new Chefe();


Encarregado encarregado = new Encarregado();


Funcionario funcionario = new Funcionario();


chefe.metodo(encarregado);

chefe.metodo(funcionario);


encarregado.metodo(chefe);

encarregado.metodo(funcionario);


funcionario.metodo(chefe);

funcionario.metodo(encarregado);

}


}



Quando fiz isso:



Chefe chefe = new Chefe();


Encarregado encarregado = new Encarregado();


Funcionario funcionario = new Funcionario();

Obtive:





Clique na imagem para ampliar



POREM CUIDADO:


Dentro do Frame
metodo(Object argumento) eu estou me referênciando ao Objeto como se fosse um Object, oque implica em:

Nesse exemplo:

funcionario.metodo(chefe);

Eu obtive:




Clique na imagem para ampliar

Oque Significa que eu SO TENHO ACESSO A PARTE java.lang.Object DO MEU OBJETO, ou seja desse Jeito eu não posso nem invocar:

argumento.metodo
(Parametros); // Isso da erro de Compilação ja que argumento aponta PARA O TIPO java.lang.Object do Objeto.


EM invocações:


chefe.metodo(encarregado);

chefe.metodo(funcionario);


encarregado.metodo(chefe);

encarregado.metodo(funcionario);


funcionario.metodo(chefe);

funcionario.metodo(encarregado);



Simplesmente passei o endereço de memória referente ao objeto, nesse exemplo seria assim:

encarregado.metodo(funcionario);
encarregado.metodo(0xA3);

chefe.metodo(encarregado);
chefe.metodo(0xA2);

funcionario.metodo(chefe);
funcionario.metodo(0xA1);


Cast de Objetos:

Em algunas casos recebo como parametro uma referência de um objeto de uma SubClasse e como argumentos tenho uma classe que é SuperClasse dela, porem quero obter as funcionabilidades específicas da SubClasse, então posso fazer cast de OBJETOS.


Vejamos o exemplo:
Lembrando que toda classe que não é declarado explicitamente nenhuma SuperClass tem java.lang.Object como SuperClasse Primária.




Clique na imagem para ampliar



public class Funcionario{

public void metodo(Object argumento){
Encarregado cast = (Encarregado) argumento; cast.exclusivo();
}

}

public class Encarregado extends Funcionario{

public void exclusivo(){
System.out.println("Metodo Exclusivo");
}

}


public class TestClass{

public static void main(String array[ ]){
Encarregado referencia = new Encarregado();
referencia.metodo(referencia);

}
}


Vejamos oque acontece quando o
referencia.metodo(referencia); sobe o Frame .metodo(referencia) na Stack de main:

Ao invocar
referencia.metodo(referencia) temos dentro do Frame: public void metodo(Object argumento):





Clique na imagem para ampliar
Nessa instrução:


Encarregado cast = (Encarregado) argumento;

Temos agora:


Clique na imagem para ampliar, Sendo a posição 0 da Local Variable a referência a Constant Pool, posição 1 argumento , posição 2 cast.

Perceba na imagem acima,
que a variavel argumento tem acesso somente a parte java.lang.Object do nosso Objeto encarregado ja a variavel cast tem acesso a Parte Encarregado do nosso Objeto, ou seja a variavel cast TEM ACESSO A TUDO DO OBJETO, por isso é possível invocar
exclusivo().


Operador instanceof:

Simplismente uma maneira de ter certeza que o cast do Objeto é aceitável, vamos supor:



Clique na imagem para ampliar



public class Funcionario{

public void metodo(Object variavelArgumento){

Encarregado variavelCast = (Encarregado) variavelArgumento;
variavelCast.
exclusivoEncarregado();

}
}

public class Encarregado extends Funcionario{

public void exclusivoEncarregado(){


}
}

public class ClasseSolta{

}

public class ClassTest{


public static void main(String array[]){

Encarregado d = new Encarregado();
ClasseSolta variavelSolta = new ClasseSolta();

d.metodo(variavelSolta);

}
}


Isso gera uma Exception. Vejamos:

Dentro da
ClassTest temos o método main nele , instanciamos um Objeto do tipo ClasseSolta, como ClasseSolta é uma SubClasse de java.lang.Object Obtemos nessa instrução, ClasseSolta variavelSolta = new ClasseSolta();// Ou seja na instanciação do Objeto

isso:




Quando invocamos:

d.metodo(variavelSolta);

Sobe-se o frame do método de assinatura:
public void metodo(Object variavelArgumento)



Clique na imagem para ampliar

Então verfica-se o seguinte,
variavelSolta é do tipo Object?

Sim variavelSolta tem uma referência a um objeto do tipo Object dentro dela também ou seja:




Seguindo Instruções:

Encarregado variavelCast = (Encarregado) variavelArgumento;
Da para a
variavelCast apontar para a parte Encarregado do objeto ao qual variavelArgumento tem uma referência?





Não, variavelArgumento é do tipo ClasseSolta que é uma SubClasse de java.lang.Object logo não tem um objeto do tipo Encarregado. Ate poderiamos fazer um cast para ClasseSolta.


Veja como o compilador tentar ver:




Clique na imagem para ampliar,- Houve a tentativa de fazer cast para que a
variavelCast aponte para a parte Encarregado do objeto porem o objeto é do tipo java.lang.Object e ClasseSolta, como vou achar algo que ela não tem?



Agora se fizer isso:

public class Funcionario{

public void metodo(Object variavelArgumento){

if(variavelArgumento instanceof Funcionario){
Encarregado variavelCast = (Encarregado) variavelArgumento;
variavelCast.exclusivoFuncionario();

}


}

}

public class Encarregado extends Funcionario{

public void exclusivoFuncionario(){

}

}

public class
ClasseSolta{

}

public class
ClassTest{

public static void main(String array[]){

Encarregado d = new Encarregado();


ClasseSolta variavelSolta = new ClasseSolta();

d.metodo(variavelSolta);


}


}

Reparte que em
ClassTest invocamos:
d.metodo(variavelSolta);

Sobe-se o frame do metodo de assinatura:
public void metodo(Object variavelArgumento)

Faz-se a verificação, o objeto
ClasseSolta a qual a variavel de referencia variavelSolta
aponta é do tipo Object também? SIM!


Então entra-se na lógica do método:

if(variavelArgumento instanceof Funcionario)

variavelArgumento aponta para um objeto do tipo ClasseSolta, essa ClasseSolta é uma SubClasse de Funcionario?
A resposta é não, porem existe uma lógica de tratamento então simplesmente o programa não executa o bloco de código do if, porem NÃO DA EXCEPTION.


Dicas sobre cast:

1 - Uma "Promoção" de objetos é permitida sem nenhum operador de cast,Sendo Funcionario a SuperClasse Direta de Encarregado, vejamos:


public class Funcionario{

}



public class Encarregado extends Funcionario{

}



public class TestClass{

public static void main(String array[ ]){

Funcionario referencia = new Encarregado();

}
}


2 - Para asseguar que não haja exception, use instanceof antes de cast



- Muito CUIDADO AO TER HERANÇA POLIMORFISMO E SOBRESCRITA DE MÉTODOS.


CYA DUDES!!!

Um comentário: