Ir al contenido principal

Conversión(casting) de variables de referencia

Seguimos con el minicurso de Java, ahora toca el tema de conversión de variables de referencia ('Reference variable casting' por su título en el examen de certificación SCJP).

Anteriormente hemos visto cómo es posible (además de común) el usar variables de referencia de tipos genéricos para referir (valga la redundancia) a objetos de tipos más específicos por medio del polimorfismo. Por ejemplo, al hablar del siguiente tramo de código debemos de identificar que ambos tipos de objetos pertenecen al mismo árbol de herencia y por lo tanto no es extraño encontrarnos con algo así:

Animal animal = new Perro();


Ahora, ¿qué sucede si queremos utilizar una variable de referencia Animal (como en el caso anterior) para invocar a un método que solamente posee la clase Perro?. Hasta este punto sabemos que la variable de tipo Animal está conteniendo realmente un Perro, no un Animal genérico cualquiera sino un Perro específicamente. En el siguiente código representamos un arreglo de animales y, en el momento que encontremos un Perro dentro del arreglo, queremos hacer algo que solo un perro puede hacer. Acordemos entonces que todo el código siguiente está correcto excepto que no estamos seguros de la línea de código que invoca al método ladrar() que es exclusivo de un Perro...

class Animal{
void respirar(){

System.out.println("Respirando como cualquier otro animal.");
}
}

class Perro extends Animal{

void respirar(){
System.out.println("Respirando como un perro.");
}

void ladrar(){
System.out.println("Guau");
}

}

class PruebaDeConversion{

public static void main (String[] args){

Animal [] a = {new Animal(), new Perro(), new Animal()};

for(Animal animal : a){

animal.respirar();

if(animal.instanceof Perro){
animal.ladrar(); //intentando hacer comportamiento de Perro
}
}

}

}

Una vez que intentamos compilar el código anterior obtenemos un error que indica más o menos lo siguiente:

cannot find symbol
 
En pocas palabras, el compilador está diciendo 'Oye, no encuentro el método ladrar() en la clase Animal'. Para que funcione debemos de hacer algo como lo siguiente:

if(animal instanceof Perro){
Perro p = (Perro) animal; //conversión de la variable de referencia
p.ladrar();
}

El nuevo y mejorado código incluye una conversión o casting, que en este caso algunas veces es llamado 'downcast' (conversión hacia un tipo inferior) debido a que estamos descendiendo en el árbol de herencia hacia un tipo de clase más específico...

SerVivo

|

|

|

v
Animal

|

|

|

v
Perro



Con esto le estamos indicando al compilador que nosotros sabemos que se está haciendo referencia hacia un objeto de tipo Perro así que no hay problema con convertir esa variable. En este caso es seguro realizar este tipo de conversión por que previamente se verifica el tipo de referencia con instanceof.

Existen algunos casos en los que no es seguro realizar esto ya que el compilador solo verifica si realmente se trata de una referencia hacia otro tipo de objeto del mismo árbol hereditario, lo cual involucra que seamos libres en hacer algo como lo siguiente:


class Animal{}

class Perro extends Animal{}

class PerroDePrueba{

public static void main (String[] args){

Animal animal = new Animal();
Perro p = (Perro) animal; //compila pero falla después
}
}

Si realizamos lo anterior nos daremos cuenta de que compila sin errores, no debería ser así por que estamos cometiendo un error pero al final de cuentas compila, sin embargo, esto no quiere decir que la aplicación funcionará ya que al ejecutar el programa nos toparemos con algo así:

java.lang.ClassCastException


Nuevamente, el compilador lo único que puede hacer por nosotros en este caso es verificar si ambos tipos de referencia pertenecen al mismo árbol de herencia, si en el código identifica algún tipo de conversión que no cumpla con esta única condición arrojará un error. P. ejemplo:

Animal animal = new Animal();
Perro p = (Perro) animal; //compila sin problemas
String cadena = (String) animal; //Error

En este caso el error que arroja es algo parecido a lo siguiente:

inconvertible types


A diferencia del downcasting, el upcasting (conversión hacia un tipo superior en el árbol de herencia) se realiza implícitamente, lo que quiere decir que no necesitas escribir el código para realizar la conversión ya que al realizar esto solamente estarás restringiendo el número de métodos que dicho objeto puede invocar, de lo contrario al downcasting que implica una probable llamada a métodos más específicos. P. ejemplo:

class Animal {}

class Perro extends Animal{

public static void main (String [] args){

Perro p = new Perro();
Animal a1 = d; //upcast correcto sin código explícito
Animal a2 = (Animal) d; //upcast correcto con código explícito
}

}


Ambas conversiones anteriores compilan y se ejecutan sin problemas ya que Perro es un Animal, lo que implica que Perro puede hacer cualquier cosa que Animal pueda.

Por último en este tema, recordemos que código como este...


Animal a = new Perro();
Perro p = (Perro) a;
a.ejecutarMetodoDePerro();

Puede convertirse en este otro equivalente...



Animal a = new Perro();
((Perro)a).ejecutarMetodoDePerro();


Éste último es menos legible pero sigue siendo correcto.

Hasta aquí le dejamos con este tema. Alguna duda o algo qué decir? Deja tu comentario. Saludox.

Comentarios

  1. Como le hago para realizar un programa que genere un arreglo de caracteres dentado dinámicamente de 5 filas, es decir, la cantidad de filas es fijo pero la cantidad de columnas se especificarán de manera aleatoria. El número mínimo de columnas será de 1 y el número máximo de 10.

    tipo-dato nombre-arreglo[ ][ ] = new tipo -dato[filas][ ];
    tabla[fila0] = new char[columnas];
    tabla[fila1] = new char[columnas];
    tabla[fila2] = new char[columnas];
    ...
    tabla[filaN] = new char[columnas];

    Después se deberá llenar cada posición del arreglo con * (asteriscos). Finalmente se mostrarán el número de columnas y todos los asteriscos correspondientes a cada fila, como se muestra en los siguientes ejemplos:

    ResponderBorrar
  2. Es un gran ejemplo, ademas es poco habitual ver el uso de 'instanceof'.El ejemplo if(animal.instanceof Perro){
    una maravilla..
    Muy bien explicado!
    Felicidades!

    ResponderBorrar
  3. Excelente explicación, leí este artículo y a pesar de estar siguiendo un libro aquí se expresó el concepto con palabras más sencillas.

    Salu2 y gracias :)

    ResponderBorrar

Publicar un comentario

Este es un espacio abierto, puedes escribir lo que gustes respetando los siguientes puntos:

1.- Lo que escribas esté relacionado con el post, si gustas contactarme puedes hacerlo aqui.

2.- Todo es cuestionable, aunque ten en cuenta que existen formas de hacerlo, evita las agresiones y revisa tu lenguaje antes de publicar un comentario.

3.- Siempre hay tres verdades: tu verdad, mi verdad y la verdad, por lo que opiniones diferentes no necesariamente son equivocadas.

4.- Los comentarios son una forma de discusión abierta, por lo que al publicar uno, implícitamente entras a una discusión, con todo lo que esto representa.

5. Me reservo el derecho de eliminar comentarios que no respeten las condiciones mencionadas anteriormente.

Toma en cuenta que puedes utilizar emoticones en tu comentario, para ver una lista de los disponibles da clic en este enlace.

Entradas más populares de este blog

3 sencillos pasos para tramitar la ayuda por desempleo de la AFORE

¿Tienes dinero ahorrado en tu AFORE y en este momento no estás trabajando o estás trabajando pero no tienes seguro social? Si respondiste sí a la pregunta anterior entonces hay una buena noticia para ti: puedes retirar una parte del dinero que tienes ahorrado. Y lo mejor, es muy sencillo. En este artículo te diré paso a paso qué hacer para obtener ese dinero, sin tecnicismos legales ni nada por el estilo, simple y sencillamente lo que necesitas saber. Paso Número 1: Obtener los últimos 2 estados de cuenta de tu Afore Esto en la mayoría de los casos es sumamente sencillo ya que dichos estados de cuenta llegan directamente al domicilio del ahorrador, si este es tu caso puedes saltar lo restante en este punto y continuar con el paso número 2, en caso contrario sigue leyendo… Si no tienes tus estados de cuenta debes ponerte en contacto con la empresa encargada de administrar tu ahorro para que te los proporcione, normalmente te van a pedir una identificación oficial, comprobante de

Conectar una base de datos en MySQL con NetBeans

NetBeans es una plataforma para el desarrollo de aplicaciones de escritorio usando Java y a un Entorno integrado de desarrollo (IDE) desarrollado usando la Plataforma NetBeans. Si eres un programador y desarrollas tus aplicaciones en Java seguramente necesitarás conectar una base de datos tipo MySQL a este entorno algún día, bueno, si lo necesitas ahora, he aquí una explicación paso a paso de cómo conectar ambas herramientas.

4 extraordinarias aplicaciones espía para Android

Le andas haciendo al James Bond y necesitas grabar video, voz o tomar fotos desde tu dispositivo Android sin ser notado? Aquí 4 excelentes aplicaciones que facilitarán tus hazañas de 007 en menos de lo que canta un gallo.

c606 c6nf5g4r6 e3 tec3ad6 [Como configurar el teclado]

¿Problemas al escribir con el teclado? ¿Tratas de escribir la letra ‘o’ y sale el número ‘6’ o algo por el estilo? La solución puede ser más simple de lo que parece. La solución a tu problema tras el salto...

Conexión, consulta y ejecución de sentencias en MySQL con Java

Anteriormente escribí este mismo artículo pero para bases de datos en Oracle . En este artículo prácticamente me copio y pego para explicar paso a paso cómo realizar la conexión a MySQL en Java, así como la forma de realizar consultas a los registros existentes y ejecutar sentencias de inserción, borrado y actualización de datos. Al final del artículo tendremos una clase que encapsulará todos los procedimientos necesarios para trabajar con la base de datos.