상속은 객체지향에서 중요한 개념이다. 상속은 구성 외에도 코드 재사용성을 향상시키는 또 다른 중요한 방법입니다. 우리는 컴포지션이 반복적으로 호출되는 객체의 기능적 인터페이스라는 것을 컴포지션에서 보았습니다. 앞으로 살펴보겠지만 상속을 사용하면 기존 클래스 정의를 재사용할 수 있습니다.
클래스 상속
이전에 클래스를 정의할 때 처음부터 시작하여 클래스의 각 멤버를 자세히 정의했습니다. 예를 들어 다음 Human 클래스는 다음과 같습니다.
다음과 같이 코드 코드를 복사합니다.
수업인간
{
/**
*접속자
*/
공개 int getHeight()
{
this.height를 반환합니다.
}
/**
* 돌연변이
*/
공공 무효 성장 높이(int h)
{
this.height = this.height + h;
}
/**
*호흡
*/
공공 공허 호흡()
{
System.out.println("후...후...");
}
개인 정수 높이;
}
위의 클래스 정의에서 클래스의 데이터 멤버, 클래스의 메서드, 클래스의 인터페이스 등 클래스의 모든 세부 사항을 이해할 수 있습니다.
이제 Woman 클래스와 같은 새 클래스를 정의하고 Woman이 Human 클래스와 매우 유사하다고 가정해야 합니다.
인간과 여성
처음부터 시작하여 이전과 같이 Woman 클래스를 완전히 정의할 수 있습니다.
다음과 같이 코드 코드를 복사합니다.
클래스 여자
{
/**
*접속자
*/
공개 int getHeight()
{
this.height를 반환합니다.
}
/**
* 돌연변이
*/
공공 무효 성장 높이(int h)
{
this.height = this.height + h;
}
/**
*호흡
*/
공공 공허 호흡()
{
System.out.println("후...후...");
}
/**
* 새로운 방법
*/
공공 휴먼 giveBirth()
{
System.out.println("아이를 낳으세요");
return(새 인간(20));
}
개인 정수 높이;
}
프로그래머는 위의 프로그램을 작성할 때 많은 고민을 하게 됩니다. Human 클래스에 많은 정의가 작성되었지만 다시 입력해야 합니다. Woman 클래스는 새로운 giveBirth() 메소드만 추가합니다(이 메소드는 새로운 Human 객체를 생성하고 반환합니다).
상속을 사용하면 위의 중복을 피할 수 있습니다. Woman 클래스가 Human 클래스를 상속받도록 하면 Woman 클래스는 자동으로 Human 클래스의 모든 공용 멤버의 기능을 갖게 됩니다.
상속을 나타내기 위해 확장 키워드를 사용합니다:
다음과 같이 코드 코드를 복사합니다.
클래스 여성이 인간을 확장합니다.
{
/**
* 새로운 방법
*/
공공 휴먼 giveBirth()
{
System.out.println("아이를 낳으세요");
return(새 인간(20));
}
}
이런 방식으로 우리는 많은 타이핑 시간을 절약할 수 있습니다. 상속을 통해 파생 클래스라는 새 클래스를 만듭니다. 상속받은 클래스(Human)를 기본 클래스(기본 클래스)라고 합니다. 파생 클래스는 기본 클래스를 자체 정의의 기반으로 사용하고 기본 클래스에 정의되지 않은 giveBirth() 메서드를 보완합니다. 상속 관계는 다음과 같이 표현될 수 있습니다.
상속: 화살표는 기본 클래스를 가리킵니다.
다음 Test 클래스를 사용하여 테스트할 수 있습니다.
다음과 같이 코드 코드를 복사합니다.
공개 수업 테스트
{
공개 정적 무효 메인(문자열[] 인수)
{
여자 aWoman = 새로운 여자();
aWoman.growHeight(120);
System.out.println(aWoman.getHeight());
}
}
파생 레이어
상속을 통해 Woman 클래스를 만듭니다. 전체 프로세스는 기본 클래스 정의, 파생 클래스 정의 및 외부 사용의 세 가지 수준으로 나눌 수 있습니다.
기본 클래스 정의 수준은 위의 Human 클래스 정의와 같이 정상적으로 클래스를 정의하는 수준입니다.
외부 사용자(예: Test 클래스에서 생성된 Woman 클래스 개체)의 관점에서 파생 클래스에는 통합된 외부 인터페이스가 있습니다.
외부 사용자의 경우 위의 인터페이스로 충분합니다. 인터페이스 관점에서만 보면 파생 클래스에는 특별한 것이 없습니다.
그러나 프로그래머는 파생 클래스 정의 수준에서 작업할 때 주의해야 합니다.
첫째, 인터페이스가 혼합되어 있습니다. getHeight() 및 GrowthHeight() 메서드는 기본 클래스에서 나오는 반면, giveBirth() 메서드는 파생 클래스 내에 정의됩니다.
더 많은 합병증이 있습니다. 이전에는 클래스 내에서 클래스의 멤버에 자유롭게 액세스할 수 있었습니다(이를 사용하여 개체를 참조함). 그러나 Woman 클래스의 정의 범위 내에 있는 경우 기본 클래스 Human의 전용 멤버에 액세스할 수 없습니다. 우리는 private의 의미를 기억합니다. private 멤버는 클래스 내부에서만 사용됩니다. Woman 클래스는 Human 클래스와는 다른 새로운 클래스이므로 Human 클래스 외부에 위치합니다. 파생 클래스에서는 기본 클래스의 전용 멤버에 액세스할 수 없습니다.
그러나 흥미로운 점은 우리의 learnHeight() 및 getHeight() 메소드가 여전히 작동한다는 것입니다. 이는 기본 클래스의 비공개 멤버가 존재하지만 직접 액세스할 수 없음을 보여줍니다.
개념을 명확히 하기 위해서는 파생 클래스 객체의 생성 메커니즘을 이해해야 합니다. 파생 클래스의 객체를 생성할 때 Java는 실제로 기본 클래스 객체(하위 객체)를 먼저 생성하고, 파생 클래스에 의해 정의된 다른 멤버를 파생 클래스 객체로 구성합니다. 외부 사용자가 볼 수 있는 것은 기본 클래스와 파생 클래스의 공개 멤버입니다. 아래와 같이:
기본 클래스 객체와 파생 클래스 객체
그림의 노란색은 기본 클래스 개체입니다. 기본 레이어의 구성원은 서로 액세스할 수 있습니다(기본 클래스 개체를 참조하려면 Human 클래스 정의에서 이를 사용합니다).
파란색 부분은 파생 개체의 새 콘텐츠입니다. 저는 이 부분을 파생 레이어라고 부릅니다. 파란색과 노란색 부분이 함께 파생 개체를 형성합니다. 파생 레이어의 구성원은 서로 접근할 수 있습니다(여성의 정의에서). 게다가 기본 레이어의 공개 멤버에도 접근할 수 있습니다. 이러한 이유로 super 키워드를 사용하여 기본 클래스 객체를 참조하고 super.member를 사용하여 기본(공용) 멤버를 나타냅니다.
파생 레이어에 있을 때(즉, Woman 클래스를 정의할 때) 빨간색 기본 전용 멤버에 액세스할 수 없습니다. 외부에 있을 때는 보라색 파생 레이어 전용 멤버나 빨간색 기본 레이어 전용 멤버에 액세스할 수 없습니다.
(파생 레이어의 프라이빗 멤버는 접근 제한이 있어 슬래시로 표시했습니다. 베이스 레이어의 프라이빗 멤버는 접근 제한이 가장 많아 십자 슬래시로 표시했습니다.)
Super는 이와 유사하며 암시적 매개변수이기도 합니다. 클래스 정의의 다른 수준에 있을 때 이는 다른 의미를 갖게 됩니다. this 및 super 키워드에 주의하세요.
(Java는 this와 super의 사용을 강요하지 않습니다. Java는 많은 경우 멤버의 소유권을 자동으로 식별할 수 있습니다. 하지만 이것이 좋은 습관이라고 생각합니다.)
보호됨
이전에는 회원의 외부 가시성을 제어하는 두 가지 접근 권한 관련 키워드인 private 및 public을 도입했습니다. 이제 새로운 액세스 키워드인 protected를 소개합니다.
보호됨으로 표시된 멤버는 이 클래스와 해당 파생 클래스에서 볼 수 있습니다. 이 개념은 이해하기 쉽습니다. 즉, 아래와 같이 기본 클래스의 보호된 멤버는 파생 계층에서 액세스할 수 있지만 외부에서는 액세스할 수 없습니다.
메서드 재정의
파생 클래스 개체의 외부 인터페이스는 궁극적으로 기본 클래스 개체의 공용 멤버와 파생 계층의 공용 멤버로 구성됩니다. 기본 클래스의 공개 멤버와 파생 레이어의 공개 멤버의 이름이 동일한 경우 Java 인터페이스에는 어떤 이름이 표시됩니까?
우리는 Java가 호출할 메소드를 결정하기 위해 메소드 이름과 매개변수 목록을 모두 사용한다는 것을 생성자와 메소드 오버로딩에서 이미 언급했습니다. 메소드는 메소드 이름과 매개변수 목록에 따라 결정됩니다. 위의 문제에서 메소드 이름만 동일하고 매개변수 목록이 다른 경우 두 메소드가 동시에 인터페이스에 표시되므로 문제가 발생하지 않습니다. 외부 호출을 수행할 때 Java는 제공된 매개변수를 기반으로 사용할 메소드(메서드 오버로딩)를 결정합니다.
메소드 이름과 매개변수 목록이 모두 동일하면 어떻게 되나요? 레이어를 파생할 때 super 및 this를 사용하여 레이어가 어떤 메서드인지 결정할 수도 있습니다. 외부에서는 통합 인터페이스만 제공하므로 동시에 두 가지 방법을 제공할 수 없습니다. 이 경우 Java는 기본 계층 메서드 대신 파생 계층 메서드를 렌더링합니다.
이 메커니즘을 메서드 재정의라고 합니다. 메서드 재정의는 기본 클래스 멤버의 메서드를 수정하는 데 유용하게 사용될 수 있습니다. 예를 들어 파생 레이어, 즉 Woman을 정의할 때 기본 클래스에서 제공하는 Breath() 메서드를 수정할 수 있습니다.
다음과 같이 코드 코드를 복사합니다.
클래스 여성이 인간을 확장합니다.
{/**
* 새로운 방법
*/
공공 휴먼 giveBirth()
{
System.out.println("아이를 낳으세요");
return(새 인간(20));
}
/**
* Human.breath() 재정의
*/
공공 공허 호흡()
{
super.breath();
System.out.println("su...");
}
}
현재 우리는 파생 레이어에 있으며 여전히 super를 통해 기본 클래스 객체의 Breath() 메서드를 호출할 수 있습니다. Woman 클래스를 외부에서 호출하면 메서드 재정의로 인해 더 이상 기본 클래스 개체의 메서드를 호출할 수 없습니다.
메서드 재정의는 기본 클래스 개체의 인터페이스를 유지하고 파생 계층의 구현을 사용합니다.
건설자
기본 클래스 객체와 파생 레이어의 개념을 이해하고 나면 파생 클래스의 생성 방법을 더 쉽게 이해할 수 있습니다.
파생 클래스 정의에서 클래스와 동일한 이름을 가진 생성자를 정의해야 합니다. 이 생성자에서:
1. 파생 객체 생성 시에는 기본 클래스 객체가 먼저 생성되고 초기화되므로 기본 클래스의 생성자를 먼저 호출해야 합니다. super(인수 목록) 문을 사용하여 기본 클래스의 생성자를 호출할 수 있습니다.
2. 기본 클래스 객체가 생성된 후 파생 레이어 구축을 시작합니다(파생 레이어 멤버 초기화). 이는 일반적인 구축 방법과 동일하며, 구축 방법 및 메소드 오버로딩을 참조하세요.
예를 들어 다음 프로그램에서 Human 클래스에는 생성자가 있습니다.
다음과 같이 코드 코드를 복사합니다.
수업인간
{
/**
* 생성자
*/
공개 인간(int h)
{
this.높이 = h;
}
/**
*접속자
*/
공개 int getHeight()
{
this.height를 반환합니다.
}
/**
* 돌연변이
*/
공공 무효 성장 높이(int h)
{
this.height = this.height + h;
}
/**
*호흡
*/
공공 공허 호흡()
{
System.out.println("후...후...");
}
개인 정수 높이;
}
파생 클래스인 Woman 클래스의 정의와 그 구성 방법은 다음과 같습니다.
다음과 같이 코드 코드를 복사합니다.
클래스 여성이 인간을 확장합니다.
{
/**
* 생성자
*/
공개 여성(int h)
{
super(h); // 기본 클래스 생성자
System.out.println("안녕하세요, 판도라!");
}
/**
* 새로운 방법
*/
공공 휴먼 giveBirth()
{
System.out.println("아이를 낳으세요");
return(새 인간(20));
}
/**
* Human.breath() 재정의
*/
공공 공허 호흡()
{
super.breath();
System.out.println("su...");
}
}
요약
연장하다
메서드 재정의
보호됨
super.member, 슈퍼()