CodeGym /Blog Java /Random-ES /Constructores de clase base
Autor
Volodymyr Portianko
Java Engineer at Playtika

Constructores de clase base

Publicado en el grupo Random-ES
¡Hola! La última vez hablamos de constructores y aprendimos mucho sobre ellos. Ahora vamos a hablar sobre los constructores de clases base .
Constructores de clase base - 1
¿ Qué es una clase base ? Tiene que ver con el hecho de que en Java varias clases diferentes pueden tener un origen común.
Constructores de clase base - 2
Esto se llama herencia . Varias clases secundarias pueden tener un ancestro común. Por ejemplo, imagina que tenemos una Animalclase:

public class Animal {
  
   String name;
   int age;
}
Podemos declarar 2 clases secundarias: Caty Dog. Esto se hace usando la palabra clave extends .

public class Cat extends Animal {

}

public class Dog extends Animal {
  
}
Podemos encontrar esto útil en el futuro. Por ejemplo, si hay una tarea para atrapar ratones, crearemos un Cat objeto en nuestro programa. Si la tarea es perseguir un palo, entonces usaremos un Dog objeto. Y si creamos un programa que simule una clínica veterinaria, funcionará con la Animal clase (y así podrá tratar tanto a gatos como a perros). Es muy importante recordar que cuando se crea un objeto, primero se llama al constructor de su clase base . Solo después de que finaliza ese constructor, el programa ejecuta el constructor de la clase correspondiente al objeto que estamos creando. En otras palabras, al crear un Catobjeto, primero se ejecuta elAnimal constructor y solo después se ejecuta elCatconstructor ejecutado . Para ver esto, agregue alguna salida de consola a los constructores Caty Animal.

public class Animal {

   public Animal() {
       System.out.println("Animal constructor executed");
   }
}


public class Cat extends Animal {

   public Cat() {
       System.out.println("Cat constructor executed!");
   }

   public static void main(String[] args) {
       Cat cat = new Cat();
   }
}
Salida de la consola: ¡ Constructor de animales ejecutado! ¡Constructor de gatos ejecutado! De hecho, ¡funciona de esa manera! ¿Por qué? Una razón es evitar la duplicación de campos compartidos entre las dos clases. Por ejemplo, todos los animales tienen corazón y cerebro, pero no todos los animales tienen cola. Podríamos declarar los campos del cerebro y del corazón , que son comunes a todos los animales, en la Animalclase padre y un campo de la cola en la Catsubclase. . Ahora declararemos un Catconstructor de clase que toma argumentos para los 3 campos.

public class Cat extends Animal {

   String tail;

   public Cat(String brain, String heart, String tail) {
       this.brain = brain;
       this.heart = heart;
       this.tail = tail;
   }

   public static void main(String[] args) {
       Cat cat = new Cat("Brain", "Heart", "Tail");
   }
}
Nota: El constructor funciona correctamente a pesar de que la Catclase no tiene campos de cerebro y corazón . Estos campos se "heredan" de la Animalclase base. La clase heredera tiene acceso a los campos de la clase base , por lo que son visibles en nuestra Catclase. Como resultado, no necesitamos duplicar estos campos en la Catclase. Podemos tomarlos de la Animalclase. Además, podemos llamar explícitamente al constructor de la clase base en el constructor de la clase secundaria. Una clase base también se denomina " superclase ". Es por eso que Java usa la palabra clave super para indicar la clase base. En el ejemplo anterior

public Cat(String brain, String heart, String tail) {
       this.brain = brain;
       this.heart = heart;
       this.tail = tail;
   }
Asignamos por separado cada campo en nuestra clase principal. En realidad, no tenemos que hacer esto. Es suficiente llamar al constructor de la clase principal y pasar los argumentos necesarios:

public class Animal {

   String brain;
   String heart;

   public Animal(String brain, String heart) {
       this.brain = brain;
       this.heart = heart;
   }

public class Cat extends Animal {

   String tail;

   public Cat(String brain, String heart, String tail) {
       super(brain, heart);
       this.tail = tail;
   }

   public static void main(String[] args) {
       Cat cat = new Cat("Brain", "Heart", "Tail");
   }
}
En el Catconstructor, llamamos al Animalconstructor y pasamos dos campos. Solo teníamos un campo para inicializar explícitamente: tail , que no está en Animal. ¿Recuerdas que mencionamos que el constructor de la clase principal se llama primero cuando se crea un objeto? ¡Es por eso que super() siempre debe estar primero en un constructor! De lo contrario, se violará la lógica del constructor y el programa generará un error.

public class Cat extends Animal {

   String tail;

   public Cat(String brain, String heart, String tail) {
       this.tail = tail;
       super(brain, heart);// Error!
   }

   public static void main(String[] args) {
       Cat cat = new Cat("Brain", "Heart", "Tail");
   }
}
El compilador sabe que cuando se crea un objeto de una clase secundaria, primero se llama al constructor de la clase base. Y si intenta cambiar manualmente este comportamiento, el compilador no lo permitirá.

Cómo se crea un objeto

Anteriormente vimos un ejemplo con una clase base y principal: Animaly Cat. Usando estas dos clases como ejemplos, ahora veremos el proceso de creación de un objeto e inicialización de variables. Sabemos que existen variables estáticas y de instancia (no estáticas) . También sabemos que la Animalclase base tiene variables y la Catclase secundaria tiene las suyas propias. Para mayor claridad, agregaremos una variable estática a cada una de las clases Animaly Cat. La variable animalCountAnimal en la clase representará el número total de especies animales en la Tierra, y catCountvariable significará el número de especies de gatos. Además, asignaremos valores iniciales a todas las variables no estáticas en ambas clases (que luego se cambiarán en el constructor).

public class Animal {

   String brain = "Initial value of brain in the Animal class";
   String heart = "Initial value of heart in the Animal class";

   public static int animalCount = 7700000;

   public Animal(String brain, String heart) {
       System.out.println("Animal base class constructor is running");
       System.out.println("Have the variables of the Animal class already been initialized?");
       System.out.println("Current value of static variable animalCount = " + animalCount);
       System.out.println("Current value of brain in the Animal class = " + this.brain);
       System.out.println("Current value of heart in the Animal class = " + this.heart);
       System.out.println("Have the variables of the Cat class already been initialized?");
       System.out.println("Current value of static variable catCount = " + Cat.catCount);

       this.brain = brain;
       this.heart = heart;
       System.out.println("Animal base class constructor is done!");
       System.out.println("Current value of brain = " + this.brain);
       System.out.println("Current value of heart = " + this.heart);
   }
}

public class Cat extends Animal {

   String tail = "Initial value of tail in the Cat class";

   static int catCount = 37;

   public Cat(String brain, String heart, String tail) {
       super(brain, heart);
       System.out.println("The cat class constructor has started (The Animal constructor already finished)");
       System.out.println("Current value of static variable catCount = " + catCount);
       System.out.println("Current value of tail = " + this.tail);
       this.tail = tail;
       System.out.println("Current value of tail = " + this.tail);
   }

   public static void main(String[] args) {
       Cat cat = new Cat("Brain", "Heart", "Tail");
   }
}
Así que estamos creando una nueva instancia de la Catclase, que hereda Animal. Hemos agregado algunos resultados detallados de la consola para ver qué sucede y en qué orden. Esto es lo que se mostrará cuando Catse cree un objeto: El constructor de la clase base Animal se está ejecutando. ¿Ya se han inicializado las variables de la clase Animal? Valor actual de variable estática animalCount = 7700000 Valor actual de cerebro en la clase Animal = Valor inicial de cerebro en la clase Animal Valor actual de corazón en la clase Animal = Valor inicial de corazón en la clase Animal Ya tiene las variables de la clase Gato sido inicializado? Valor actual de la variable estática catCount = 37 ¡El constructor de la clase base Animal está listo! Valor actual de cerebro = Cerebro Valor actual corazón = Corazón El constructor de la clase gato ha comenzado (El constructor Animal ya ha terminado) Valor actual de la variable estática catCount = 37 Valor actual de cola = Valor inicial de cola en la clase Gato Valor actual de cola = Cola Entonces, ahora podemos ver claramente el orden de inicialización de variables y llamadas al constructor cuando se crea un nuevo objeto:
  1. Las variables estáticas de la clase base ( Animal) se inicializan. En nuestro caso, la variable animalCountAnimal de la clase se establece en 7700000.

  2. Las variables estáticas de la clase secundaria ( Cat) se inicializan.

    Nota: todavía estamos dentro del Animalconstructor y ya hemos mostrado:

    El constructor de la clase base Animal se está ejecutando.
    ¿Ya se han inicializado las variables de la clase Animal?
    Valor actual de variable estática animalCount = 7700000
    Valor actual de cerebro en la clase Animal = Valor inicial de cerebro en la clase Animal
    Valor actual de corazón en la clase Animal = Valor inicial de corazón en la clase Animal
    Tener las variables de la clase Gato ya sido inicializado?
    Valor actual de la variable estática catCount = 37


  3. Luego se inicializan las variables no estáticas de la clase base . Les asignamos específicamente valores iniciales, que luego se reemplazan en el constructor. El constructor Animal aún no ha terminado, pero ya se han asignado los valores iniciales de cerebro y corazón:

    El constructor de la clase base Animal se está ejecutando.
    ¿Ya se han inicializado las variables de la clase Animal?
    Valor actual de la variable estática animalCount = 7700000
    Valor actual del cerebro en la clase Animal = Valor inicial del cerebro en la clase Animal
    Valor actual del corazón en la clase Animal = Valor inicial del corazón en la clase Animal


  4. Se inicia el constructor de la clase base .
    Ya nos hemos convencido de que este paso es el cuarto: en los primeros tres pasos al comienzo del Animalconstructor, ya se han asignado valores a muchas variables.


  5. Los campos no estáticos de la clase secundaria ( Cat) se inicializan.
    Esto sucede antes de que el Catconstructor comience a ejecutarse.
    Cuando comienza a ejecutarse, la variable cola ya tiene un valor:

    El constructor de la clase gato ha comenzado (El constructor Animal ya terminó) Valor actual de la variable estática catCount = 37 Valor actual de la cola = Valor inicial de la cola en la clase Gato


  6. El constructor de la Catclase secundaria se llama

    ¡Y así es como se ve la creación de un objeto en Java!

    Debo decir que no somos grandes fanáticos del aprendizaje de memoria, pero es mejor memorizar el orden de inicialización de variables y llamadas al constructor .

    Esto aumentará en gran medida su comprensión del flujo del programa y el estado de sus objetos en cualquier momento en particular.

    Además, muchas clases no usan la herencia. En este caso, no se aplican los pasos relacionados con la clase base.

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION