La herencia es un pilar importante de OOP (Programación Orientada a Objetos) . Es el mecanismo en Java por el cual una clase puede heredar las características ( campos y métodos ) de otra clase.
Hay dos formas en que los objetos se pueden inicializar mientras se heredan las propiedades de las clases padre e hijo. Están:
- Child c = new Child(): El uso de esta inicialización es acceder a todos los miembros presentes en las clases padre e hijo, ya que estamos heredando las propiedades.
- Parent p = new Child(): este tipo de inicialización se usa para acceder solo a los miembros presentes en la clase principal y los métodos que se anulan en la clase secundaria. Esto se debe a que la clase principal se convierte en la clase secundaria.
¿Qué es upcasting?
Upcasting es el encasillamiento de un objeto hijo a un objeto padre . El upcasting se puede hacer implícitamente. Upcasting nos brinda la flexibilidad de acceder a los miembros de la clase principal, pero no es posible acceder a todos los miembros de la clase secundaria mediante esta función. En lugar de todos los miembros, podemos acceder a algunos miembros específicos de la clase secundaria. Por ejemplo, podemos acceder a los métodos anulados .
Ejemplo: Sea una clase animal . Puede haber muchas clases diferentes de animales. Una de esas clases es Fish . Entonces, supongamos que la clase fish extiende la clase Animal . Por lo tanto, las dos formas de herencia, en este caso, se implementan como:
Entendamos el siguiente código para encontrar la diferencia:
// Java program to demonstrate // the concept of upcasting // Animal Class class Animal { String name; // A method to print the // nature of the class void nature() { System.out.println("Animal"); } } // A Fish class which extends the // animal class class Fish extends Animal { String color; // Overriding the method to // print the nature of the class @Override void nature() { System.out.println("Aquatic Animal"); } } // Demo class to understand // the concept of upcasting public class GFG { // Driver code public static void main(String[] args) { // Creating an object to represent // Parent p = new Child(); Animal a = new Fish(); // The object 'a' has access to // only the parent's properties. // That is, the colour property // cannot be accessed from 'a' a.name = "GoldFish"; // This statement throws // a compile-time error // a.color = "Orange"; // Creating an object to represent // Child c = new Child(); Fish f = new Fish(); // The object 'f' has access to // all the parent's properties // along with the child's properties. // That is, the colour property can // also be accessed from 'f' f.name = "Whale"; f.color = "Blue"; // Printing the 'a' properties System.out.println("Object a"); System.out.println("Name: " + a.name); // This statement will not work // System.out.println("Fish1 Color" +a.color); // Access to child class - overriden method // using parent reference a.nature(); // Printing the 'f' properties System.out.println("Object f"); System.out.println("Name: " + f.name); System.out.println("Color: " + f.color); f.nature(); } }
Object a Name: GoldFish Aquatic Animal Object f Name: Whale Color: Blue Aquatic Animal
Una figura ilustrativa del programa:
- Del ejemplo anterior, se puede entender claramente que no podemos acceder a los miembros de la clase secundaria utilizando una referencia de clase principal aunque sea del tipo secundario. Eso es:
// This statement throws // a compile-time error a.color = "Orange";
- Y del ejemplo anterior, también podemos observar que podemos acceder a los miembros de la clase principal y a los métodos anulados de la clase secundaria utilizando el mismo objeto de referencia de la clase principal. Eso es:
// Access to child class // overridden method a.nature();
- Por lo tanto, podemos concluir que el propósito principal de usar estas dos sintaxis diferentes es lograr una variación en el acceso a los miembros respectivos de las clases.