JavaRush /Java Blog /Random-KO /중첩 클래스의 상속

중첩 클래스의 상속

Random-KO 그룹에 게시되었습니다
안녕하세요! 오늘 우리는 중첩 클래스의 상속이라는 중요한 메커니즘의 작동을 살펴보겠습니다. 다른 클래스로부터 중첩 클래스를 상속해야 할 때 무엇을 할지 생각해 본 적이 있는지 모르겠습니다. 그렇지 않다면 저를 믿으십시오. 여기에는 많은 뉘앙스가 있기 때문에 이 상황은 혼란스러울 수 있습니다.
  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좌석을 선언했습니다. 경주용 좌석의 특별한 하위 유형이 이로부터 물려받았습니다 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