JavaRush /Java Blog /Random-TW /嵌套類別的繼承

嵌套類別的繼承

在 Random-TW 群組發布
你好!今天我們來看看嵌套類別中一個重要機制的運作方式—繼承。我不知道你是否想過當你需要從其他類別繼承一個嵌套類別時你會做什麼。如果沒有,請相信我:這種情況可能會令人困惑,因為這裡有很多細微差別:
  1. 我們是從某個類別繼承巢狀類,還是從巢狀類別繼承另一個類別?
  2. 繼承者/繼承者是常規的公共類,還是也是巢狀類別?
  3. 最後,我們在所有這些情況下使用的嵌套類別到底是什麼類型?
如果你回答了所有這些問題,就會有太多可能的答案,讓你頭暈目眩:) 如你所知,為了解決一個複雜的問題,你需要將其分成更簡單的部分。這就是我們要做的。我們從兩個角度依序來看每組嵌套類別:誰可以繼承該類型的嵌套類,以及它可以繼承誰。讓我們從靜態巢狀類別開始。

靜態巢狀類

內部類別的繼承範例 - 2他們的繼承規則是最簡單的。在這裡您幾乎可以做任何您想做的事情。靜態巢狀類別可以繼承自:
  • 普通班
  • 在外部類別或其祖先中聲明的靜態巢狀類
讓我們記住講座中有關靜態巢狀類別的範例。
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
讓我們嘗試更改程式碼並創建一個靜態嵌套類別Drawing及其後代 - Boeing737Drawing
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }

   public static class Boeing737Drawing extends Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
正如你所看到的,沒問題。我們可以完全刪除該類Drawing,並將其設為常規公共類,而不是靜態嵌套類 - 不會有任何變更。
public class Drawing {

}

public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Boeing737Drawing extends Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
就這麼解決了 哪些類別可以從靜態巢狀類別繼承?幾乎任何!嵌套/常規、靜態/非靜態 - 沒關係。Boeing737Drawing這裡我們從靜態巢狀類別繼承內部類別Drawing
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }

   public class Boeing737Drawing extends Drawing {

       public int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Boeing737Drawing您可以像這樣 建立一個實例:
public class Main {

   public static void main(String[] args) {

      Boeing737 boeing737 = new Boeing737(1990);
      Boeing737.Boeing737Drawing drawing = boeing737.new Boeing737Drawing();
      System.out.println(drawing.getMaxPassengersCount());

   }

}
雖然我們的類別Boeing737Drawing是繼承自靜態類,但它本身並不是靜態的!因此它總是需要外部類別的實例。我們可以把課程Boeing737Drawing從課堂中拿出來Boeing737,讓它變成公開課。什麼都不會改變——它也可以從靜態嵌套繼承Drawing
public class Boeing737 {

   private int manufactureYear;
   public static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }
}

public class Boeing737Drawing extends Boeing737.Drawing {

   public int getMaxPassengersCount() {

       return Boeing737.maxPassengersCount;

}
唯一重要的一點:在這種情況下,我們需要將靜態變數maxPassengersCount公開。如果它保持私有,普通的公共類別將無法存取它。我們整理出了靜態類別!:) 現在讓我們繼續討論內部類別。正如您所記得的,它們有 3 種類型:簡單內部類別、本地類別和匿名內部類別。 內部類別的繼承範例 - 3再一次,讓我們從簡單到複雜:)

匿名內部類別

匿名內部類別不能從另一個類別繼承。任何其他類別都不能從匿名類別繼承。簡單得不能再簡單了!:)

本地課程

本機類別(以防您忘記)在另一個類別的程式碼區塊內聲明。最常見的是 - 在這個外部類別的某些方法內。從邏輯上講,只有同一方法(或區塊)中的其他本地類別可以從本地類別繼承。這是一個例子:
public class PhoneNumberValidator {

   public void validatePhoneNumber(final String number) {

       class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }

           public String getPhoneNumber() {
               return phoneNumber;
           }

           public void setPhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

       class CellPhoneNumber extends PhoneNumber {

       }

       class LandlinePhoneNumber extends PhoneNumber {


       }

       //...code валидации номера
   }
}
這是我們有關本地課程的講座中的代碼。在數位驗證器類別中,我們有一個本地類別PhoneNumber- 電話號碼。如果出於我們的目的,我們需要將兩個單獨的實體從中分離出來,例如,行動電話號碼和固定電話號碼,我們只能在相同的方法中執行此操作。原因很簡單:本地類別的範圍位於聲明它的方法(區塊)內。因此,我們將無法以某種方式在外部使用它(包括繼承)。然而,本地類別本身俱有更廣泛的繼承可能性!本地類別可以繼承自:
  1. 正常上課。
  2. 在與本地類別或其祖先相同的類別中聲明的內部類別。
  3. 來自在同一方法(區塊)中聲明的另一個本地類別。
第一點和第三點看起來很明顯,但第二點有點令人困惑:/讓我們來看兩個例子。範例 1 - “從與本機類別在同一類別中宣告的內部類別繼承本機類別”:
public class PhoneNumberValidator {

   class PhoneNumber {

       private String phoneNumber;

       public PhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }

       public String getPhoneNumber() {
           return phoneNumber;
       }

       public void setPhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }
   }

   public void validatePhoneNumber(final String number) {

       class CellPhoneNumber extends PhoneNumber {

           public CellPhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       class LandlinePhoneNumber extends PhoneNumber {

           public LandlinePhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       //...code валидации номера
   }
}
在這裡,我們將類別PhoneNumber從方法中取出validatePhoneNumber()並使其成為內部的而不是本地的。這並不妨礙我們繼承它的 2 個本地類別。範例 2 – “…或在這個類別的祖先中。” 這就是事情變得更有趣的地方。我們可以把它帶到PhoneNumber更高的繼承鏈。讓我們聲明一個抽象類AbstractPhoneNumberValidator,它將成為我們的祖先PhoneNumberValidator
public abstract class AbstractPhoneNumberValidator {

   class PhoneNumber {

       private String phoneNumber;

       public PhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }

       public String getPhoneNumber() {
           return phoneNumber;
       }

       public void setPhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }
   }

}
正如你所看到的,我們不僅聲明了它,而且還將內部類別移入其中PhoneNumber。然而,在其後代類別中——PhoneNumberValidator方法中的本地類別可以繼承PhoneNumber
public class PhoneNumberValidator extends AbstractPhoneNumberValidator {

   public void validatePhoneNumber(final String number) {

       class CellPhoneNumber extends PhoneNumber {

           public CellPhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       class LandlinePhoneNumber extends PhoneNumber {

           public LandlinePhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       //...code валидации номера
   }
}
由於透過繼承進行連接,後代類別中的本地類別「看到」祖先類別中的內部類別。最後,讓我們繼續最後一組:)

內部類別

內部類別可以被同一外部類別(或其後代)中聲明的另一個內部類別繼承。讓我們使用內部類講座中的自行車範例來看看這一點。
public class Bicycle {

   private String model;
   private int mawWeight;

   public Bicycle(String model, int mawWeight) {
       this.model = model;
       this.mawWeight = mawWeight;
   }

   public void start() {
       System.out.println("Go!");
   }

   class Seat {

       public void up() {

           System.out.println("Сидение поднято выше!");
       }

       public void down() {

           System.out.println("Сидение опущено ниже!");
       }
   }

   class SportSeat extends Seat {

       //...methods
   }
}
這裡我們在類別內部Bicycle聲明了一個內部類別Seat——seat。賽車座椅的特殊子類型繼承自它 - SportSeat。但是,我們可以創建一種單獨類型的“賽車”並將其放入單獨的類別中:
public class SportBicycle extends Bicycle {

   public SportBicycle(String model, int mawWeight) {
       super(model, mawWeight);
   }


   class SportSeat extends Seat {

       public void up() {

           System.out.println("Сидение поднято выше!");
       }

       public void down() {

           System.out.println("Сидение опущено ниже!");
       }
   }
}
這也是有可能的。子層級的內部類別 ( SportBicycle.SportSeat) 「看到」祖先的內部類別並且可以繼承它們。從內部類別繼承有一個非常重要的特性!在前面的兩個例子中,我們SportSeat有內在的。但是,如果我們決定將其設為SportSeat常規公共類,並且它也繼承自內部類,該怎麼辦Seat
//ошибка! No inclosing instance of  type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {

   public SportSeat() {

   }

   public void up() {

       System.out.println("Сидение поднято выше!");
   }

   public void down() {

       System.out.println("Сидение опущено ниже!");
   }
}
我們遇到錯誤!你能猜出它與什麼有關嗎?:) 這很簡單。當我們討論內部類別時Bicycle.Seat,我們提到內部類別的建構子隱式傳遞了對外部類別物件的參考。因此,不創建物件Bicycle就無法創建物件Seat。創作呢SportSeat?它沒有與 中相同的內建機制來隱式傳遞對建構函式中外部類別物件的參考Seat。但是,如果沒有對象Bicycle,就像有的情況一樣Seat,我們無法建立對象SportSeat。因此,我們只剩下一件事要做——明確地將SportSeat物件的引用傳遞給建構函數。Bicycle其操作方法如下:
class SportSeat extends Bicycle.Seat {

   public SportSeat(Bicycle bicycle) {

       bicycle.super();
   }

   public void up() {

       System.out.println("Сидение поднято выше!");
   }

   public void down() {

       System.out.println("Сидение опущено ниже!");
   }
}
為此,我們使用一個特殊的詞super(); 現在,如果我們想創建一個對象SportSeat,沒有什麼可以阻止我們這樣做:
public class Main {

   public static void main(String[] args) {

       Bicycle bicycle = new Bicycle("Peugeot", 120);
       SportSeat peugeotSportSeat = new SportSeat(bicycle);

   }
}
唷,講座內容相當大:)但是你學到了很多新東西!現在是解決一些問題的時候了!:)
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION