CodeGym /Blog Java /Random-ES /Ampliación y reducción de los tipos de referencia
Autor
John Selawsky
Senior Java Developer and Tutor at LearningTree

Ampliación y reducción de los tipos de referencia

Publicado en el grupo Random-ES
¡Hola! En una lección anterior, discutimos la conversión de tipos primitivos. Recordemos brevemente lo discutido. Ampliación y reducción de tipos de referencia - 1Imaginamos tipos primitivos (en este caso, tipos numéricos) como muñecos de anidación que varían en tamaño según la cantidad de memoria que ocupan. Como recordarás, poner un muñeco más pequeño dentro de uno más grande es sencillo tanto en la vida real como en la programación Java.

public class Main {
   public static void main(String[] args) {
       int bigNumber = 10000000;
       short smallNumber = (short) bigNumber;
       System.out.println(smallNumber);
   }
}
Este es un ejemplo de conversión o ampliación automática . Ocurre por sí mismo, por lo que no necesita escribir código adicional. Al final, no estamos haciendo nada inusual: simplemente estamos poniendo una muñeca más pequeña en una muñeca más grande. Otra cosa es si intentamos hacer lo contrario y poner una muñeca rusa más grande en una muñeca más pequeña. No puedes hacer eso en la vida real, pero en programación sí. Pero hay un matiz. Si tratamos de poner an inten una shortvariable, las cosas no nos salen tan bien. Después de todo, la shortvariable solo contiene 16 bits de información, ¡pero intocupa 32 bits! Como resultado, el valor pasado se distorsiona. El compilador nos dará un error (' Amigo, ¡estás haciendo algo sospechoso!'). Pero si indicamos explícitamente el tipo al que estamos convirtiendo nuestro valor, seguirá adelante y realizará la operación.

public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
Eso es justo lo que hicimos en el ejemplo anterior. La operación se realizó, pero debido a que la shortvariable puede acomodar solo 16 de los 32 bytes, el valor final se distorsiona y obtenemos el número -27008 . Tal operación se denomina conversión explícita o estrechamiento .

Ejemplos de ampliación y reducción de tipos de referencia

¡Ahora hablemos de los mismos operadores aplicados no a tipos primitivos, sino a objetos y variables de referencia ! ¿Cómo funciona esto en Java? En realidad es bastante simple. Hay objetos que no están relacionados. Sería lógico suponer que no se pueden convertir entre sí, ni explícita ni automáticamente:

public class Cat {
}

public class Dog {
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Dog(); // Error!

   }

}
Aquí, por supuesto, obtenemos un error. Las clases Caty Dogno están relacionadas entre sí, y no hemos escrito un 'conversor' para pasar de una a otra. Tiene sentido que no podamos hacer esto: el compilador no tiene idea de cómo convertir estos objetos de un tipo a otro. Si los objetos están relacionados, bueno, ¡eso es otro asunto! Relacionado ¿cómo? Sobre todo, a través de la herencia. Intentemos usar la herencia para crear un pequeño sistema de clases. Tendremos una clase común para representar animales:

public class Animal {

   public void introduce() {

       System.out.println("I'm Animal");
   }
}
Todo el mundo sabe que los animales pueden ser domesticados (mascotas) o salvajes:

public class WildAnimal extends Animal {

   public void introduce() {

       System.out.println("I'm WildAnimal");
   }
}

public class Pet extends Animal {

   public void introduce() {

       System.out.println("I'm Pet");
   }
}
Por ejemplo, tome caninos, tenemos perros domésticos y coyotes:

public class Dog extends Pet {

   public void introduce() {

       System.out.println("I'm Dog");
   }
}



public class Coyote extends WildAnimal {

   public void introduce() {

       System.out.println ("I'm Coyote");
   }
}
Elegimos específicamente las clases más básicas para que sean más fáciles de entender. Realmente no necesitamos ningún campo, y un método es suficiente. Intentemos ejecutar este código:

public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
¿Qué crees que se mostrará en la consola? ¿Se invocará el introducemétodo de la Petclase o la Animalclase? Intenta justificar tu respuesta antes de continuar leyendo. ¡Y aquí está el resultado! Soy mascota ¿Por qué obtuvimos eso? Es todo sencillo. Tenemos una variable padre y un objeto descendiente. Al escribir,

Animal animal = new Pet();
ampliamos una Petreferencia y la asignamos a una Animalvariable. Al igual que con los tipos primitivos, los tipos de referencia se amplían automáticamente en Java. No necesita escribir código adicional para que esto suceda. Ahora tenemos un objeto descendiente asignado a una referencia principal. Como resultado, vemos que la llamada al método se realiza en la clase descendiente. Si aún no comprende completamente por qué funciona este código, vuelva a escribirlo en un lenguaje sencillo:

Animal animal = new DomesticatedAnimal();
No hay problema con esto, ¿verdad? Imagina que esto es la vida real, y la referencia es simplemente una etiqueta de papel con 'Animal' escrito en ella. Si tomas ese papel y lo adjuntas al collar de cualquier mascota, todo estará correcto. ¡Después de todo, cualquier mascota es un animal! El proceso inverso, bajar el árbol de herencia a los descendientes, se está estrechando:

public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
Como puede ver, aquí indicamos claramente la clase a la que queremos convertir nuestro objeto. Anteriormente teníamos una WildAnimalvariable y ahora tenemos un Coyote, que está más abajo en el árbol de herencia. Tiene sentido que sin una indicación explícita el compilador no permita tal operación, pero si indicamos el tipo entre paréntesis, entonces todo funciona. Ampliación y reducción de tipos de referencia - 2Considere otro ejemplo más interesante:

public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal(); // Error!
   }
}
¡El compilador genera un error! ¿Pero por qué? Porque está intentando asignar un objeto principal a una referencia descendiente. En otras palabras, estás tratando de hacer algo como esto:

DomesticatedAnimal domesticatedAnimal = new Animal();
Bueno, tal vez todo funcione si especificamos explícitamente el tipo al que estamos tratando de convertir. Eso funcionó con números. ¡Vamos a intentarlo! :)

public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
Excepción en el subproceso "principal" java.lang.ClassCastException: ¡El animal no se puede convertir en un error de mascota! El compilador no nos gritó esta vez, pero terminamos con una excepción. Ya sabemos el motivo: estamos tratando de asignar un objeto padre a una referencia descendiente. Pero, ¿por qué exactamente no puedes hacer eso? Porque no todos los Animales son Animales Domesticados. Ha creado un Animalobjeto y está tratando de asignarlo a una Petvariable. Un coyote también es un Animal, pero no es un Pet. En otras palabras, cuando escribes

Pet pet = (Pet) new Animal();
new Animal()podría representar cualquier animal, ¡no necesariamente una mascota! Naturalmente, su Pet petvariable solo es apta para almacenar Mascotas (y sus descendientes) y no cualquier tipo de animal. Es por eso que ClassCastExceptionse creó una excepción especial de Java, para los casos en los que se produce un error durante la conversión de clases. Repasémoslo de nuevo para aclarar las cosas. Una referencia principal puede apuntar a instancias de una clase descendiente:

public class Main {

   public static void main(String[] args) {

       Pet pet = new Pet();
       Animal animal = pet;

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
Por ejemplo, aquí no tenemos problemas. Tenemos un Petobjeto referenciado por una Petvariable. Más tarde, una Animalreferencia apuntaba al mismo objeto. Después de eso, convertimos animala un archivo Pet. Por cierto, ¿por qué funcionó eso para nosotros? ¡La última vez tuvimos una excepción! ¡ Porque esta vez nuestro objeto original es un Pet!

Pet pet = new Pet();
Pero en el último ejemplo, era un Animalobjeto:

Pet pet = (Pet) new Animal();
No puede asignar un objeto antepasado a una variable descendiente. Puedes hacer lo contrario.
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION