안녕하세요! 오늘 우리는 중첩 클래스의 상속이라는 중요한 메커니즘의 작동을 살펴보겠습니다. 다른 클래스로부터 중첩 클래스를 상속해야 할 때 무엇을 할지 생각해 본 적이 있는지 모르겠습니다. 그렇지 않다면 저를 믿으십시오. 여기에는 많은 뉘앙스가 있기 때문에 이 상황은 혼란스러울 수 있습니다.
- 일부 클래스에서 중첩 클래스를 상속합니까, 아니면 중첩 클래스에서 다른 클래스를 상속합니까?
- 후계자/상속 클래스는 일반 공개 클래스인가요, 아니면 중첩 클래스인가요?
- 마지막으로, 이러한 모든 상황에서 정확히 어떤 유형의 중첩 클래스를 사용하고 있습니까?
정적 중첩 클래스
그들의 상속 규칙은 가장 간단합니다. 여기에서는 마음이 원하는 거의 모든 것을 할 수 있습니다. 정적 중첩 클래스는 다음에서 상속될 수 있습니다.- 정규 수업
- 외부 클래스나 그 조상에 선언된 정적 중첩 클래스
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 {
}
//...code валидации номера
}
}
이것은 지역 수업에 대한 강의에서 나온 코드입니다. PhoneNumber
번호 유효성 검사기 클래스 안에는 로컬 클래스 인 전화번호가 있습니다 . 우리의 목적을 위해 휴대폰 번호와 유선 전화번호 등 두 개의 별도 엔터티를 분리해야 하는 경우 동일한 방법 내에서만 이를 수행할 수 있습니다. 이유는 간단합니다. 로컬 클래스의 범위는 해당 클래스가 선언된 메서드(블록) 내에 있습니다. 따라서 우리는 이를 외부적으로(상속을 포함하여) 사용할 수 없습니다. 그러나 지역 클래스 자체는 상속 가능성이 더 넓습니다! 로컬 클래스는 다음에서 상속할 수 있습니다.
- 정규 수업.
- 로컬 클래스와 동일한 클래스 또는 해당 상위 클래스에 선언된 내부 클래스입니다.
- 동일한 메서드(블록)에 선언된 다른 로컬 클래스에서.
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);
}
}
휴, 강의 내용이 꽤 컸네요 :) 그런데 새로운 걸 많이 배웠네요! 이제 몇 가지 문제를 해결할 시간입니다! :)
GO TO FULL VERSION