CodeGym /Java Blog /무작위의 /중첩 클래스 상속의 예
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다시, 간단한 것에서 복잡한 것으로 이동합시다 :)

익명의 내부 클래스

익명 내부 클래스는 다른 클래스를 상속할 수 없습니다. 다른 클래스는 익명 클래스를 상속할 수 없습니다. 이보다 더 간단할 수는 없습니다! :)

지역 수업

로컬 클래스(잊은 경우)는 다른 클래스의 코드 블록 내에서 선언됩니다. 대부분의 경우 이것은 외부 클래스의 일부 메서드 내에서 발생합니다. 논리적으로 동일한 메서드(또는 코드 블록) 내의 다른 로컬 클래스만 로컬 클래스를 상속할 수 있습니다. 다음은 예입니다.

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. 그러나 의 생성은 어떻습니까 SportSeat? 와 달리 Seat생성자에게 외부 클래스의 인스턴스에 대한 참조를 암시적으로 전달하는 기본 제공 메커니즘이 없습니다. 의 경우와 마찬가지로 객체가 없으면 객체를 Bicycle생성할 수 없습니다 . 따라서 우리가 해야 할 일은 단 하나뿐입니다. 개체 에 대한 참조를 생성자 에게 명시적으로 전달하는 것입니다 . 방법은 다음과 같습니다. SportSeatSeatSportSeatBicycle

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!");
   }
}
Now를 사용하여 수퍼클래스 생성자를 호출합니다 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