Pode parecer um assunto batido, mas será que não tem uns "peguinhas" para quem está de olho no exame para certificação?
Convertendo variáveis de referência.
Este assunto tem uma relação com polimorfismo. A mágica do polimorfismo está em você poder referenciar um tipo mais específico com uma variável de um tipo mais genérico.
Isto é possível porque o compilador verifica a árvore de herança das classes envolvidas neste processo, veja:
public class Veiculo{
public void informaLotacao(){
System.out.println("Um motorista.");
}
}
public class Ferrari extends Veiculo{
public void informaLotacao(){
System.out.println("Um motorista e um passageiro.");
}
public void informaPotencia(){
System.out.println("460 cavalos.");
}
}
public class Onibus extends Veiculo{
public void informaLotacao(){
System.out.println("Um motorista e trinta e dois passageiros.");
}
public void informaCombustivel(){
System.out.println("Diesel.");
}
}
public class TestaVeiculo{
public static void main(String[] args){
Veiculo ferrari = new Ferrari();
Veiculo onibus = new Onibus();
System.out.println("Uma ferrari tem espaço para " + ferrari.informaLotacao() + " e possui " + ferrari.informaPotencia());
System.out.println("Um ônibus tem espaco para " + onibus.informaLotacao() + " e funciona com " + onibus.informaCombustivel());
}
}
Ao executar TestaVeiculo que saída você espera receber?
Na verdade, vai acontecer um erro de compilação dizendo cannot find symbol. Isso porque as referências são do tipo Veiculo, que não possui o metodo informaPotencia() e nem informaCombustivel().
Entenda que você só pode chamar os métodos que o tipo da sua variável de referência expõe para você, mesmo que seja uma referência para uma instância de um tipo mais especializado, com mais métodos.
Para acessar os métodos do tipo especializado temos primeiro que converter os tipos, veja:
public class TestaVeiculo{
public static void main(String[] args){
Veiculo ferrari = new Ferrari();
Veiculo onibus = new Onibus();
Ferrari ferrariConvertida = (Ferrari) ferrari;
Onibus onibusConvertido = (Onibus) onibus;
System.out.println("Uma ferrari tem espaço para " + ferrariConvertida.informaLotacao() + " e possui " + ferrariConvertida.informaPotencia());
System.out.println("Um ônibus tem espaco para " +
onibusConvertido.informaLotacao() + " e funciona com " +
onibusConvertido.informaCombustivel());
}
}
Agora você fez as pazes com o compilador, realizando o cast (conversão) de sua referência generica para um tipo mais específico, que expõe os métodos que você quer usar. Tudo certo! Mas pense comigo: já que o compilador olha apenas para a árvore de herança, o que aconteçe em uma situação assim:
public class TestaVeiculo{
public static void main(String[] args){
Veiculo ferrari = new Veiculo();
Veiculo onibus = new Veiculo();
Ferrari ferrariConvertida = (Ferrari) ferrari;
Onibus onibusConvertido = (Onibus) onibus;
System.out.println("Uma ferrari tem espaço para " + ferrariConvertida.informaLotacao() + " e possui " +
ferrariConvertida.informaPotencia());
System.out.println("Um ônibus tem espaco para " +
onibusConvertido.informaLotacao() + " e funciona com " +
onibusConvertido.informaCombustivel());
}
}
Bom neste caso, você prova que o compilador só olha para a árvore de herança, porque ele não vai reclamar de nada. Entretanto, ao executar o código você vai receber um java.lang.ClassCastException, porque as variáveis de referência ferrari e onibus agora são do tipo Veiculo e um tipo generalizado não cabe em um tipo especializado, ou seja, Ferrari é um Veiculo, mas Veiculo, não necessariamente, é uma Ferrari. Ou ainda, Veiculo pode ser um Onibus, que é bem diferente de uma Ferrari, concorda?
Saber o que não compila e o que compila e não roda é fundamental para o exame.
Forte abraço e até a próxima.
Mauricio da Silva Marinho.
Mostrando postagens com marcador certificação. Mostrar todas as postagens
Mostrando postagens com marcador certificação. Mostrar todas as postagens
sexta-feira, 2 de novembro de 2012
[Java] Overloading ou Overriding? (Parte 1/2)
Qual a diferença entre estas duas técnicas de programação OO? O que significam?
Overloading (Sobrecarga).
Um método sobrecarregado é aquele que aparece mais de uma vez em uma classe (ou subclasse) com assinatura (lista de argumentos) distinta.
O tipo de retorno e a implementação, podem ser, opcionalmente diferentes. Então podemos dizer que métodos sobrecarregados:
Veja o seguinte exemplo de método sobrecarregado:
class Aritmetica{
public int soma(int a, int b){
return a + b;
}
public double soma(double a, double b){
return a + b;
}
}
//Chamando o metodo soma sobrecarregado.
public class TestaAritmetica{
public static void main(String[] args){
Aritmetica calculadora = new Aritmetica();
int a = 10;
int b = 20;
int somaDosInts = calculadora.soma(a, b);
int somaDosDoubles = calculadora.soma(10.5 + 20.5);
}
}
No exemplo anterior, na classe TestaAritmetica, somaDosInts recebe o retorno da chamada a primeira forma do método sobrecarregado Aritmetica.soma que é soma(int, int). E somaDosDoubles recebe o retorno da chamada a segunda forma do método sobrecarregado Aritmetica.soma, que é soma(double, double). É um método polimórfico, pois tem mais de uma forma.
É o tipo de argumento que irá acionar a forma chamada de um método sobrecarregado, pois a identidade do método é dada pela sua assinatura. Veja este outro exemplo:
class Pet{}
class Cao extends Pet{}
class Lar{
public void maisUmNaFamilia(Pet pet){
System.out.println("Chegou um pet na casa!");
}
public void maisUmNaFamilia(Cao cao){
System.out.println("Chegou um cão na casa!");
}
public static void main(String[] args){
Lar lar = new Lar();
Pet pet = new pet();
Cao cao = new Cao();
Pet refParaCao = new Cao();
lar.maisUmNaFamilia(pet);
lar.maisUmNaFamilia(cao);
lar.maisUmNaFamilia(refParaCao);
}
}
E no caso do exemplo anterior, qual seria a saída?
Lembre-se: a forma do método sobrecarregado será identificada pelos tipos da lista de parâmetros, pela assinatura do método. Logo, independente de refParaCao guardar uma referência de Cao, seu tipo é Pet e por isso o método forma do método sobregarregado Lar.maisUmNaFamilia que será invocada é: Lar.maisUmNaFamilia(Pet). Potanto a saída será:
Chegou um pet na casa!
Chegou um cao na casa!
Chegou um pet na casa!
É isso aí! Estes conhecimentos são cobrados na prova SCJP/OCJP e espero que lhe ajudem a esclarecer algumas questões importantes. No próximo post discutiremos Overriding, as confusões entre os dois conceitos e como o examinador pode se aproveitar disso para lhe confundir no exame.
Forte abraço,
Mauricio da Silva Marinho
Overloading (Sobrecarga).
Um método sobrecarregado é aquele que aparece mais de uma vez em uma classe (ou subclasse) com assinatura (lista de argumentos) distinta.
O tipo de retorno e a implementação, podem ser, opcionalmente diferentes. Então podemos dizer que métodos sobrecarregados:
- devem possuir assinaturas distintas.
- podem possuir tipos de retorno distintos.
- podem possuir modificadores de acesso distintos.
- podem declarar exceções verificadas novas ou mais abrangentes.
Veja o seguinte exemplo de método sobrecarregado:
class Aritmetica{
public int soma(int a, int b){
return a + b;
}
public double soma(double a, double b){
return a + b;
}
}
//Chamando o metodo soma sobrecarregado.
public class TestaAritmetica{
public static void main(String[] args){
Aritmetica calculadora = new Aritmetica();
int a = 10;
int b = 20;
int somaDosInts = calculadora.soma(a, b);
int somaDosDoubles = calculadora.soma(10.5 + 20.5);
}
}
No exemplo anterior, na classe TestaAritmetica, somaDosInts recebe o retorno da chamada a primeira forma do método sobrecarregado Aritmetica.soma que é soma(int, int). E somaDosDoubles recebe o retorno da chamada a segunda forma do método sobrecarregado Aritmetica.soma, que é soma(double, double). É um método polimórfico, pois tem mais de uma forma.
É o tipo de argumento que irá acionar a forma chamada de um método sobrecarregado, pois a identidade do método é dada pela sua assinatura. Veja este outro exemplo:
class Pet{}
class Cao extends Pet{}
class Lar{
public void maisUmNaFamilia(Pet pet){
System.out.println("Chegou um pet na casa!");
}
public void maisUmNaFamilia(Cao cao){
System.out.println("Chegou um cão na casa!");
}
public static void main(String[] args){
Lar lar = new Lar();
Pet pet = new pet();
Cao cao = new Cao();
Pet refParaCao = new Cao();
lar.maisUmNaFamilia(pet);
lar.maisUmNaFamilia(cao);
lar.maisUmNaFamilia(refParaCao);
}
}
E no caso do exemplo anterior, qual seria a saída?
Lembre-se: a forma do método sobrecarregado será identificada pelos tipos da lista de parâmetros, pela assinatura do método. Logo, independente de refParaCao guardar uma referência de Cao, seu tipo é Pet e por isso o método forma do método sobregarregado Lar.maisUmNaFamilia que será invocada é: Lar.maisUmNaFamilia(Pet). Potanto a saída será:
Chegou um pet na casa!
Chegou um cao na casa!
Chegou um pet na casa!
É isso aí! Estes conhecimentos são cobrados na prova SCJP/OCJP e espero que lhe ajudem a esclarecer algumas questões importantes. No próximo post discutiremos Overriding, as confusões entre os dois conceitos e como o examinador pode se aproveitar disso para lhe confundir no exame.
Forte abraço,
Mauricio da Silva Marinho
Assinar:
Postagens (Atom)