1. Encasillamiento
Las variables que almacenan tipos de referencia (clases) también se pueden convertir a diferentes tipos. Pero esto solo funciona dentro de una jerarquía de un solo tipo. Veamos un ejemplo sencillo. Supongamos que tenemos la siguiente jerarquía de clases, en la que las clases de abajo heredan las clases de arriba.
El encasillamiento de tipos de referencia, así como de tipos primitivos, también se clasifica como de ampliación y de estrechamiento.
Vemos que la clase Gato hereda la clase Mascota, y la clase Mascota, a su vez, hereda la clase Animal.
Si escribimos código como este:
Animal kitten = new Cat();
Esta es una conversión de tipo de ampliación . También se denomina conversión implícita. Hemos ampliado la referencia al gato para que ahora se refiera a un objeto Gato . Con una conversión de tipo como esta, no podremos usar la referencia gatito para llamar a métodos que están presentes en la clase Gato pero ausentes en la clase Animal .
Una conversión de estrechamiento (o conversión explícita) ocurre en la dirección opuesta:
Cat cat = (Cat) kitten;
Indicamos explícitamente que queremos convertir la referencia almacenada en la variable gatito (cuyo tipo es Animal ) al tipo Gato .
2. Comprobar el tipo de un objeto
Pero hay que tener mucho cuidado aquí. Si haces esto:
Animal beast = new Cat();
Wolf grayWolf = (Wolf) beast;
El compilador permitirá este código, ¡pero habrá un error cuando se ejecute el programa! La JVM lanzará una excepción:
Exception in thread "main" java.lang.ClassCastException: Cat cannot be cast to a Wolf
Las referencias a un objeto Gato solo se pueden almacenar en variables cuyo tipo sea un ancestro de la clase Gato: Mascota, Animal u Objeto.
¿Porqué es eso?
El punto relevante aquí es que una referencia de objeto se usa para referirse a los métodos y variables de ese objeto . Y no habrá ningún problema si usamos una variable Animal para almacenar una referencia a un objeto Cat: el tipo Cat siempre tiene variables y métodos del tipo Animal , ¡los heredó!
Pero si la JVM nos permitiera almacenar una referencia a un objeto Cat en una variable Wolf, entonces podríamos tener una situación en la que podríamos intentar usar la variable grayWolf para llamar a un método que no existe en el objeto Cat almacenado en esa variable. . Es por eso que este arreglo no está permitido.
Java tiene un operador especial instanceof
que le permite verificar si un objeto es de cierto tipo y, por lo tanto, puede almacenarse en una variable de cierto tipo. Parece bastante simple:
variable instanceof Type
Ejemplo:
Animal beast = new Cat();
if (beast instanceof Wolf)
{
Wolf grayWolf = (Wolf) beast;
}
Este código no causará errores, incluso en tiempo de ejecución.
Aquí hay algunos ejemplos más que ilustran la situación:
Conversión de tipo de ensanchamiento | Descripción |
---|---|
|
Esta es una conversión de ampliación clásica: no se requiere ningún operador de conversión de tipos. Ahora solo los métodos definidos en la En la |
Conversión de tipo de estrechamiento | |
|
Conversión de restricción clásica: debe agregar una verificación de tipo y un operador de conversión. La Cow cow variable almacena una referencia a un Whale objeto. Verificamos que este sea el caso , y luego realizamos una conversión de tipo (estrechamiento). O como también se le llama:
un tipo de elenco
.
|
|
Puede limitar un tipo de referencia sin comprobar el tipo del objeto. Si la cow variable hace referencia a un objeto que no es un , se generará Whale un .InvalidClassCastException |
3. Llamar al método original: la super
palabra clave
Cuando anulamos el método de una clase principal, a veces, en lugar de reemplazarlo con el nuestro, solo queremos complementarlo ligeramente.
Sería genial si pudiéramos usar el método de la clase principal en nuestro método y luego ejecutar algo de nuestro propio código. O tal vez ejecutar primero nuestro propio código y luego llamar al método de la clase principal.
Y Java nos permite hacer precisamente eso. Para llamar a un método de la clase padre, haga esto:
super.method(arguments);
Ejemplos:
class PeaceTime
{
public double getPi()
{
return 3.14;
}
}
class WarTime extends PeaceTime
{
public double getPi()
{
return super.getPi()*2; // 3.14*2
}
}
¡En tiempos de guerra, el valor de Pi
puede ser mayor que 6! Por supuesto, estamos bromeando, pero este ejemplo demuestra cómo puede funcionar todo esto.
Aquí hay un par de ejemplos más para aclarar un poco las cosas:
Código | Descripción |
---|---|
|
Cow y Whale clases |
|
La salida de pantalla será:
|
Esto es algo difícil. Honestamente, es una de las cosas más difíciles en OOP . Dicho esto, necesitas saberlo y entenderlo.
GO TO FULL VERSION