JavaRush /Java Blog /Random-TW /基類構造函數

基類構造函數

在 Random-TW 群組發布
你好!上次我們討論了構造函數,我們學到了很多關於它們的知識。現在我們將討論基類構造函數這樣的東西。什麼是基類?事實上,在 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