Não sei se alguem já notou mas as anotações sobre Java que estou postando aqui são apropriadas para quem vai prestar o exame SCJP (Sun Certified Java Programmer).
Como também pretendo ser um programador certificado pela Sun, estou estudando e quero aproveitar para compartilhar com você meus resumos.
Hoje vou falar sobre o objetivo 5.2 do exame que é sobre Conversão de Variáveis de Referência (também conhecido por Cast ou Casting de tipos):
Dado um cenário, desenvolver código que demonstre o uso do polimorfismo. Além disso, determinar quando a conversão será necessária e saber diferenciar erros de compilação de erros de tempo de execução relacionados a conversão de referências a objetos.
Temos 2 pontos principais neste objetivo:
Uso do polimorfismo e saber diferenciar erros de compilação e de tempo de execução.
Veja também que no final está"referências a objetos".
Isto quer dizer que esse tipo de conversão não é como conversão entre tipos primitivos (que não será abordado neste post).
Vamos começar analisando o código:
Upcasting ou Conversão ampliadora
Considerando o código acima poderíamos naturalmente fazer as seguintes declarações:
Porque? Tipos genéricos podem apontar para tipos mais específicos. Isto chama-seupcasting ou conversão ampliadora. Esta conversão é sempre segura, pois estamos indo de um tipo mais específico para um mais genérico (de baixo pra cima na árvore de herança) e sabemos que a superclasse poderá fazer tudo que a subclasse fazia pois herdou dela. Mas fazendo isto estamos perdendo os métodos de Dog.
Nesse caso a variável de referência animal que é do tipo Animal faz referência a Dog e isto é possível porque Dog É-UM Animal (Este relacionamento É-UM significa que Dog extends Animal).
Por estes motivos o compilador permite fazer o cast sem nenhuma notação especial nem nada explícito.
Até aqui tudo bem, mas e se tentar realizar um comportamento mais específico? Por exemplo, tentar chamar um método que só existe em Dog? Não pode porque só comportamentos de Animal serão aceitos:
O código não compila porque animal não tem o método rolar(). Entenda que estamos transformando um Dog num tipo mais genérico e que ele agora só poderá executar ações deste novo tipo. Ele perdeu os comportamentos específicos que tinha.
Mas um coisa interessante é que se Dog sobrescrever algum método de Animal, qual dos métodos será executado? Vamos modificar o código:
Suponhamos que faça a seguinte chamada:
Quem vai comer? Animal ou Dog? Neste caso o método em Dog seria executado porque ele sobrescreveu. Então quando fazemos o upcasting perdemos os métodos do subtipo mas se algum for sobrescrito a versão a ser executada é a do subtipo. Muito louco isso não é?
Downcasting
Seguindo a raciocínio do upcasting, se quisermos "voltar" um tipo genérico para o mais específico (conversão redutora), devemos fazer a conversão explicitamente:
Veja que mudamos apenas o tipo da variável, não o tipo da referência. Então esta conversão se torna possível pois animal faz referência a Dog.
Então você se pergunta: Porque o upcasting é automático e o downcasting não? Agora chegamos num ponto interessante: No upcasting a conversão nunca falha. Nodowncasting, nem sempre teremos esta certeza. No exemplo citado acima, a conversão deu certo porque animal fazia referência a Dog mas e se não fizesse? Se animal fizesse referência a Animal mesmo?
Como isso poderá ser feito se Animal não é um Dog? Animal nem sabe da existência de Dog. A conversão não pode ser feita porque os tipos são incompatíveis.
Só que o mais intrigante vem agora: O código compila!
Se você usa o Eclipse vá em Project > Clean..., selecione seu projeto e veja se apareceu algum erro em Problems? Não vai aparecer nada, porque pro compilador está tudo bem, ele não sabe e nem quer saber se animal faz referência a Animal ou Dog. Mas quando tentar executar:
Exception in thread "main" java.lang.ClassCastException: Animal cannot be cast to Dog
at Animal.main(Animal.java:46)
Então não tente converter um objeto para um tipo que ele não é. Mas lembre-se que o compilador não sabe se você vai tentar isto.
Para saber se dada conversão é aceita devemos usar o operador instanceof. Este operador retorna true ou false para uma comparação entre tipos:
Na IDE Eclipse, quando começar a digitar "ins" e pressionar Ctrl + Barra de espaço ele já sugere o operador, então pressionando Enter ele já vai preencher um bloco de código igual a este:
Aí é só você ir dando TAB e preenchendo os campos. Ele faz isso porque sabe que quase sempre que usamos o instanceof é pra saber se um objeto é de determinado tipo, e sendo positivo, já queremos que o objeto seja convertido neste tipo.
Aproveitando que já dei essa dica, tem outras duas que eu também uso muito para criar o método main e pro comando System.out.println: Para o main apenas digite main e Ctrl + Barra de espaço, para o println digite sysout Ctrl + Barra de espaço.
Só por curiosidade: Podemos converter qualquer objeto no tipo Object, como já falei no outro post, o Object é como uma classe "mãe" no Java:
Mas essa conversão não tem muita utilidade pois faz com que animal perca todos seus métodos como já foi explicado. Por hoje é só!
Bons estudos e boas conversões!
Fonte(Javacomcafe)
Como também pretendo ser um programador certificado pela Sun, estou estudando e quero aproveitar para compartilhar com você meus resumos.
Hoje vou falar sobre o objetivo 5.2 do exame que é sobre Conversão de Variáveis de Referência (também conhecido por Cast ou Casting de tipos):
Dado um cenário, desenvolver código que demonstre o uso do polimorfismo. Além disso, determinar quando a conversão será necessária e saber diferenciar erros de compilação de erros de tempo de execução relacionados a conversão de referências a objetos.
Temos 2 pontos principais neste objetivo:
Uso do polimorfismo e saber diferenciar erros de compilação e de tempo de execução.
Veja também que no final está"referências a objetos".
Isto quer dizer que esse tipo de conversão não é como conversão entre tipos primitivos (que não será abordado neste post).
Vamos começar analisando o código:
- //Superclasse
- public class Animal {
- void comer(){
- System.out.println("Animal comendo...");
- }
- }
- //Subclasse
- class Dog extends Animal{
- void rolar(){
- System.out.println("Dog rolando...");
- }
- }
Upcasting ou Conversão ampliadora
Considerando o código acima poderíamos naturalmente fazer as seguintes declarações:
- Animal animal; //Declarou um tipo genérico
- animal = new Dog(); //Apontou para um mais específico
- //Ou simplesmente:
- Animal animal = new Dog();
- //Ou ainda:
- Animal animal = (Animal)new Dog(); //Conversão explícita
Porque? Tipos genéricos podem apontar para tipos mais específicos. Isto chama-seupcasting ou conversão ampliadora. Esta conversão é sempre segura, pois estamos indo de um tipo mais específico para um mais genérico (de baixo pra cima na árvore de herança) e sabemos que a superclasse poderá fazer tudo que a subclasse fazia pois herdou dela. Mas fazendo isto estamos perdendo os métodos de Dog.
Nesse caso a variável de referência animal que é do tipo Animal faz referência a Dog e isto é possível porque Dog É-UM Animal (Este relacionamento É-UM significa que Dog extends Animal).
Por estes motivos o compilador permite fazer o cast sem nenhuma notação especial nem nada explícito.
Até aqui tudo bem, mas e se tentar realizar um comportamento mais específico? Por exemplo, tentar chamar um método que só existe em Dog? Não pode porque só comportamentos de Animal serão aceitos:
- animal.rolar(); //Problema! Método não definido para o tipo Animal
O código não compila porque animal não tem o método rolar(). Entenda que estamos transformando um Dog num tipo mais genérico e que ele agora só poderá executar ações deste novo tipo. Ele perdeu os comportamentos específicos que tinha.
Mas um coisa interessante é que se Dog sobrescrever algum método de Animal, qual dos métodos será executado? Vamos modificar o código:
- //Superclasse
- public class Animal {
- void comer(){
- System.out.println("Animal comendo...");
- }
- }
- //Subclasse
- class Dog extends Animal{
- void rolar(){
- System.out.println("Dog rolando...");
- }
- //Dog sobrescreveu o método comer
- void comer(){
- System.out.println("Dog comendo...");
- }
- }
Suponhamos que faça a seguinte chamada:
- Animal animal = new Dog();
- animal.comer();
Quem vai comer? Animal ou Dog? Neste caso o método em Dog seria executado porque ele sobrescreveu. Então quando fazemos o upcasting perdemos os métodos do subtipo mas se algum for sobrescrito a versão a ser executada é a do subtipo. Muito louco isso não é?
Downcasting
Seguindo a raciocínio do upcasting, se quisermos "voltar" um tipo genérico para o mais específico (conversão redutora), devemos fazer a conversão explicitamente:
- Dog dog = (Dog) animal;
- dog.comer();
Veja que mudamos apenas o tipo da variável, não o tipo da referência. Então esta conversão se torna possível pois animal faz referência a Dog.
Então você se pergunta: Porque o upcasting é automático e o downcasting não? Agora chegamos num ponto interessante: No upcasting a conversão nunca falha. Nodowncasting, nem sempre teremos esta certeza. No exemplo citado acima, a conversão deu certo porque animal fazia referência a Dog mas e se não fizesse? Se animal fizesse referência a Animal mesmo?
- Animal animal = new Animal();
- Dog dog = (Dog) animal;
Como isso poderá ser feito se Animal não é um Dog? Animal nem sabe da existência de Dog. A conversão não pode ser feita porque os tipos são incompatíveis.
Só que o mais intrigante vem agora: O código compila!
Se você usa o Eclipse vá em Project > Clean..., selecione seu projeto e veja se apareceu algum erro em Problems? Não vai aparecer nada, porque pro compilador está tudo bem, ele não sabe e nem quer saber se animal faz referência a Animal ou Dog. Mas quando tentar executar:
Exception in thread "main" java.lang.ClassCastException: Animal cannot be cast to Dog
at Animal.main(Animal.java:46)
Então não tente converter um objeto para um tipo que ele não é. Mas lembre-se que o compilador não sabe se você vai tentar isto.
Para saber se dada conversão é aceita devemos usar o operador instanceof. Este operador retorna true ou false para uma comparação entre tipos:
- if (dog instanceof Animal)
- {
- System.out.println("dog é um Animal.");
- }
Na IDE Eclipse, quando começar a digitar "ins" e pressionar Ctrl + Barra de espaço ele já sugere o operador, então pressionando Enter ele já vai preencher um bloco de código igual a este:
- if (name instanceof type) {
- type new_name = (type) name;
- }
Aí é só você ir dando TAB e preenchendo os campos. Ele faz isso porque sabe que quase sempre que usamos o instanceof é pra saber se um objeto é de determinado tipo, e sendo positivo, já queremos que o objeto seja convertido neste tipo.
Aproveitando que já dei essa dica, tem outras duas que eu também uso muito para criar o método main e pro comando System.out.println: Para o main apenas digite main e Ctrl + Barra de espaço, para o println digite sysout Ctrl + Barra de espaço.
Só por curiosidade: Podemos converter qualquer objeto no tipo Object, como já falei no outro post, o Object é como uma classe "mãe" no Java:
- Object obj = (Object)new Animal();
Mas essa conversão não tem muita utilidade pois faz com que animal perca todos seus métodos como já foi explicado. Por hoje é só!
Bons estudos e boas conversões!
Fonte(Javacomcafe)