CodeGym /Java 博客 /随机的 /嵌套类的继承示例
John Squirrels
第 41 级
San Francisco

嵌套类的继承示例

已在 随机的 群组中发布
你好!今天我们将了解一个重要的机制:嵌套类中的继承。你有没有想过如果你需要让一个嵌套类继承某个其他类你会怎么做。如果不是,请相信我:这种情况可能会令人困惑,因为其中有很多细微差别。
  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 {
          
          
       }

       // ...number validation 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);
           }
       }

       // ...number validation 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);
           }
       }

       // ...number validation code
   }
}
由于继承关系,后代类中的局部类“看到”祖先类中的内部类。最后,让我们继续最后一组 :)

内部类

在同一外部类(或其后代)中声明的内部类可以继承另一个内部类。让我们使用内部类课程中的自行车示例来探索这一点。

public class Bicycle {

   private String model;
   private int maxWeight;

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

   public void start() {
       System.out.println("Let's go!");
   }

   class Seat {

       public void up() {

           System.out.println("Seat up!");
       }

       public void down() {

           System.out.println("Seat down!");
       }
   }

   class SportSeat extends Seat {
      
       // ...methods
   }
}
这里我们在类Seat内部声明了内部类Bicycle。一种特殊类型的赛车座椅,SportSeat继承了它。但是,我们可以创建一个单独的“赛车”类型并将其放在一个单独的类中:

public class SportBicycle extends Bicycle {
  
   public SportBicycle(String model, int maxWeight) {
       super(model, maxWeight);
   }

  
   class SportSeat extends Seat {

       public void up() {

           System.out.println("Seat up!");
       }

       public void down() {

           System.out.println("Seat down!");
       }
   }
}
这也是一种选择。后代的内部类(SportBicycle.SportSeat)“看到”了祖先的内部类并且可以继承它们。继承内部类有一个非常重要的特性!在前面两个例子中,我们的SportSeat类是一个内部类。但是如果我们决定创建SportSeat一个同时继承内部类的普通公共类呢Seat

// Error! No enclosing instance of type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {

   public SportSeat() {

   }

   public void up() {

       System.out.println("Seat up!");
   }

   public void down() {

       System.out.println("Seat down!");
   }
}
我们得到一个错误!你能猜出为什么吗?:) 这一切都很简单。我们在讲Bicycle.Seat内部类的时候提到过,外部类实例的引用会隐式传递给内部类的构造函数。这意味着您不能Seat在不创建对象的情况下创建Bicycle对象。但是创建 a 呢SportSeat?与 不同Seat,它没有这种内置机制来隐式地将对外部类实例的引用传递给构造函数。直到,没有Bicycle对象,我们就无法创建SportSeat对象,就像 的情况一样Seat。因此,我们只剩下一件事要做——显式地将对象的SportSeat引用传递给构造函数Bicycle。方法如下:

class SportSeat extends Bicycle.Seat {

   public SportSeat(Bicycle bicycle) {

       bicycle.super();
   }

   public void up() {

       System.out.println("Seat up!");
   }

   public void down() {

       System.out.println("Seat down!");
   }
}
我们使用super(); Now 调用超类构造函数,如果我们想创建一个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