JavaRush /Java 博客 /Random-ZH /基类构造函数

基类构造函数

已在 Random-ZH 群组中发布
你好!上次我们讨论了构造函数,我们学到了很多关于它们的知识。现在我们将讨论基类构造函数这样的东西。什么是基类?事实上,在 Java 中,几个不同的类可以有一个共同的起源。 基类构造函数 - 2这就是所谓的继承。多个后代类可以有一个共同的祖先类。例如,假设我们有一个类Animal(动物):
public class Animal {

   String name;
   int age;
}
例如,我们可以为其创建 2 个后代类 -CatDog。这是使用关键字 完成的extends
public class Cat extends Animal {

}

public class Dog extends Animal {

}
这可能对我们将来有用。例如,如果任务是捉老鼠,我们会在程序中创建一个对象Cat。如果任务是在一根棍子后面运行,那么我们使用 object Dog。如果我们创建一个模拟兽医诊所的程序,它将与该类一起工作Animal(能够治疗猫和狗)。将来要记住这一点非常重要:创建对象时,首先调用其基类的构造函数,然后才调用我们正在创建的对象的类本身的构造函数。也就是说,在创建对象时,Cat类构造函数首先起作用Animal,然后才是构造函数Cat。为了确保这一点,让我们添加到构造函数CatAnimal输出到控制台。
public class Animal {

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


public class Cat extends Animal {

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

   public static void main(String[] args) {
       Cat cat = new Cat();
   }
}
控制台输出:

Отработал конструктор Animal
Отработал конструктор Cat!
事实上,这就是一切的运作方式!它是做什么用的?例如,避免重复两个类的公共字段。例如,每种动物都有心脏和大脑,但并非每种动物都有尾巴。brain我们可以在heart父类中声明所有动物共有的字段Animal,并tail在子类中声明一个字段Cat。现在我们将为该类创建一个构造函数Cat,我们将在其中传递所有 3 个字段。
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");
   }
}
注意:尽管该类Cat没有字段brain和,但构造函数成功运行heart。这些字段是从基类“拉出来”的Animal。后代类可以访问基类的字段,因此Cat它们在我们的类中是可见的。因此,我们不需要Cat在类中复制这些字段 - 我们可以从类中获取它们Animal。而且,我们可以在后代类的构造函数中显式调用基类的构造函数。基类也称为“超类”,这就是 Java 使用关键字的原因super。在前面的例子中
public Cat(String brain, String heart, String tail) {
       this.brain = brain;
       this.heart = heart;
       this.tail = tail;
   }
我们单独分配了父类中的每个字段。事实上,您不必这样做。调用父类的构造函数并向其传递必要的参数就足够了:
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");
   }
}
在构造函数中,Cat我们调用了构造函数Animal并向其传递了两个字段。我们只需要显式初始化一个tailAnimal存在的字段。还记得我们说过,当创建一个对象时,首先调用父类的构造函数吗?所以,这就是为什么这个词super()应该总是在构造函数中排在第一位的原因!否则,构造函数的逻辑将被破坏,程序将产生错误。
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");
   }
}
编译器知道,当创建后代类的对象时,首先调用基类的构造函数。而如果你尝试手动改变这种行为,它是不会允许的。

创建对象的过程。

上面我们看了一个带有基类和父类的示例 -AnimalCat。现在,我们以这两个类为例,看看创建对象和初始化变量的过程。我们知道变量有静态和实例变量(非静态)。我们还知道基类Animal有自己的变量,后代类也Cat有自己的变量。Animal为了清楚起见,我们Cat向该类添加一个静态变量。animalCount类变量Animal是地球上动物物种的总数,变量catsCount是猫物种的数量。此外,我们将为两个类的所有非静态变量分配起始值(然后将在构造函数中更改)。
public class Animal {

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

   public static int animalCount = 7700000;

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

       this.brain = brain;
       this.heart = heart;
       System.out.println("Animal base class constructor completed!");
       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 = "The initial value of tail in the Cat class";

   static int catsCount = 37;

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

   public static void main(String[] args) {
       Cat cat = new Cat("Brain", "Heart", "Tail");
   }
}
Cat因此,我们创建一个继承自 的 类的新对象Animal。让我们将详细的控制台输出添加到我们的程序中,看看会发生什么以及按什么顺序发生。这是创建对象后将输出到控制台的内容Cat

Выполняется конструктор базового класса Animal
Были ли уже проинициализированы переменные класса Animal?
Текущее meaning статической переменной animalCount = 7700000
Текущее meaning brain в классе Animal = Изначальное meaning brain в классе Animal
Текущее meaning heart в классе Animal = Изначальное meaning heart в классе Animal
Были ли уже проинициализированы переменные класса Cat?
Текущее meaning статической переменной catsCount = 37
Конструктор базового класса Animal завершил работу!
Текущее meaning brain = Мозг
Текущее meaning heart = Сердце
Конструктор класса Cat начал работу (конструктор Animal уже был выполнен)
Текущее meaning статической переменной catsCount = 37
Текущее meaning tail = Изначальное meaning tail в классе Cat
Текущее meaning tail = Хвост
所以,现在我们可以清楚地看到创建新对象时初始化变量和调用构造函数的顺序:
  1. 基类的静态变量( )被初始化。在我们的例子中,类变量被赋予值 7700000。AnimalanimalCountAnimal

  2. 后代类( )的静态变量被初始化。注意 - 我们仍在构造函数内,控制台已经显示:CatAnimal

    
        Выполняется конструктор базового класса Animal
        Были ли уже проинициализированы переменные класса Animal?
        Текущее meaning статической переменной animalCount = 7700000
        Текущее meaning brain в классе Animal = Изначальное meaning brain в классе Animal
        Текущее meaning heart в классе Animal = Изначальное meaning heart в классе Animal
        Были ли уже проинициализированы переменные класса Cat?
        Текущее meaning статической переменной catsCount = 37
  3. 接下来,初始化基类的非静态变量。我们专门为它们分配了初始值,然后在构造函数中将其更改为新值。构造函数还没有完成它的工作,但是初始值已经被赋值了:Animalbrainheart

    
        Выполняется конструктор базового класса Animal
        Были ли уже проинициализированы переменные класса Animal?
        Текущее meaning статической переменной animalCount = 7700000
        Текущее meaning brain в классе Animal = Изначальное meaning brain в классе Animal
        Текущее meaning heart в классе Animal = Изначальное meaning heart в классе Animal
  4. 基类构造函数开始工作。

    我们已经看到,这个阶段只是第四个:在前三点中,当构造函数开始工作时,Animal许多变量已经被赋值。

  5. 初始化子类的非静态字段( )。Cat

    它发生在设计师Cat开始工作之前。

    当他开始工作时,变量tail已经有了一个值:

    
    Конструктор класса Cat начал работу (конструктор Animal уже был выполнен)
    Текущее meaning статической переменной catsCount = 37
    Текущее meaning tail = Изначальное meaning tail в классе Cat
  6. 调用后代类的构造函数 Cat

这就是Java中创建对象的过程!我必须说,我们不太喜欢死记硬背,但最好记住初始化变量和调用构造函数的顺序,并为将来记住它们。这将极大地增加您对程序进度和对象在任何给定时刻的状态的理解。此外,类通常没有直接的父类(超类/基类)。在这种情况下,与基类关联的项将不会被执行。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION