자바 기초부터 차근차근...(14)
※ Chapter14 클래스의 상속1: 상속의 기본
※ 본문은 윤성우의 열혈JAVA를 정리한 글입니다.
※ 문제가 될시 비공개 처리하겠습니다.
■ 상속에 대한 매우 치명적인 오해
"상속은 코드의 재활용을 위한 문법입니다."
그러나 객체지향 기반의 개발 경험이 풍부한 개발자는 다음의 내용으로 답을 한다.
"연관된 일련의 클래스들에 대해 공통적인 규약을 정의할 수 있습니다."
지금은 이 내용이 이해가 가지 않을 수 있으나 공부하다보면 이해가 간다고 하니 알아두자.
책에서 강조하고자 하는 말은 다음과 같다.
"상속은 코드의 재활용을 목적으로 사용하는 문법이 아니다."
■ 상속의 가장 기본적인 특성
상속을 단순하게 설명하자면, 기존의 정의된 클래스에 메소드와 변수를 추가하여
새로운 클래스를 정의하는 것이 상속이다.
class Man{
String name;
public void tellYourName() {
System.out.println("My name is " + name);
}
}
이때 위의 클래스를 상속하여 다음과 같이 새로운 클래스를 정의할 수 있다.
(extends는 상속을 의미하는 키워드)
class BusinessMan extends Man { //Man 을 상속하는 클래스
String company;
String position;
public void tellYourInfo() {
System.out.println("My company is " + company);
System.out.println("My position is " + position);
tellYourName(); //Man 클래스를 상속했기 때문에 호출 가능!
}
}
이후 BusinessMan 클래스의 인스턴스를 생성하면, 다음 형태의 인스턴스가 생성된다.
BusinessMan man = new BusinessMan();
Man - 참조변수 String name : Man의 멤버 String company; String position; void tellYourName() {..} : Man의 멤버 void tellYourInfo() {..} |
BusinessMan 인스턴스에는 Man 클래스의 변수와 메소드가 존재한다.
이는 Man 클래스를 상속했기 때문이다. (tellYourName 메소드를 호출할 수 있음)
지금 설명한 내용이 '상속의 가장 기본적인 특성이다.
- 상속의 대상이 되는 클래스 -> 상위 클래스, 기초 클래스, 부모 클래스
- 상속을 하는 클래스 -> 하위 클래스, 유도 클래스, 자식 클래스
Man 클래스는 상위 클래스이고 BusinessMan 클래스는 하위 클래스이다.
UML 기호라는 것으로 다음과 같이 표현되는데 매우 널리 사용되므로 알아두자
MAN <- BusinessMan (원래 박스형태와 화살표로 표현하나 일단 이런식이란 것만...)
■ 상속과 생성자
이것은 예제를 통해서 알아보도록 하자.
상위 클래스인 Man , 그리고 이를 상속하는 하위 클래스인 BusinessMan에 적절한 생성자가 정의되어 있다.
BusinessMan의 인스턴스가 생성되면, 그 안에는 Man 클래스의 상속으로 인해 String name 변수도 존재하는데
이를 초기화해줘야 함으로 this.name = name; 이 들어간 것을 볼 수 있다.
이제 다음 예제를 보자.
위의 실행 결과는 다음 사실을 알려준다.
"하위 클래스의 인스턴스 생성 시 상위 클래스, 하위 클래스의 생성자 모두 호출된다."
"하위 클래스의 인스턴스 생성시 상위 클래스의 생성자가 먼저 호출된다."
하위 클래스의 생성자에서 상위 클래스의 생성자를 명시적으로 호출하지 않으면
인자를 받지 않는 생성자가 자동으로 호출된다.
명시적으로 호출하기 위해서는 super 키워드를 사용하면 된다.
이렇듯 생성자 내에서 사용된 키워드 super는 '상위 클래스의 생성자 호출'을 의미한다.
super(1); // 1을 인자로 전달받을 수 있는 생성자 호출
super(1,2); //1과 2을 인자로 전달받을 수 있는 생성자 호출
만약 다음과 같이 생성자의 첫 문장이 아닌 뒤에서 나올 경우 컴파일 오류가 발생한다
public SubCLS(int i) {
System.out.println(...);
super(i); // 이 위치에 있으면 컴파일 오류 발생함
}
그리고 하위 클래스의 생성자에서 상위 클래스의 생성자 호출을 생략하면
인자를 받지 않는 상위 클래스의 호출문이 자동으로 삽입된다.
public SubCLS() {
super(); // 자동으로 삽입 된 문장
System.out.println...;
}
§ 클래스 변수, 클래스 메소드와 상속
static 선언이 붙는 클래스 변수와 클래스 메소드도 상속의 대상에 포함이 되겠는가?
static 선언이 갖는 의미를 떠올리고 논리적 접근을 하면 스스로 답을 할 수 있다.
■ static 선언이 붙는 '클래스 변수'와 '클래스 메소드'의 상속
앞서 공부한 클래스 변수와 클래스 메소드의 특징을 정리하면 다음과 같다.
- 인스턴스의 생성과 상관이 없이 접근이 가능하다.
- 클래스 내부와 외부에서 접근이 가능하다. (접근 수준 지시자가 허용하면)
- 클래스 변수와 클래스 메소드가 위치한 클래스 내에서는 직접 접근이 가능하다.
클래스 변수와 클래스 메소드는 인스턴스에 속하지 않는, 딱 하나만 존재하는 변수와 메소드다.
따라서 상속의 대상이 아니다.
class SuperCLS {
static int count = 0; // 클래스 변수
public SuperCLS() {
count++; //클래스 내에서는 직접 접근이 가능
}
}
"상위 클래스에 위치한 클래스 변수와 메소드에 하위 클래스에서 어떻게 접근하는가?"
결론을 말하자면 변수의 이름만으로 접근이 가능하다.
단, 선언된 접근 수준 지시자가 접근을 허용해야 접근이 가능하다. (private 선언이면 접근불가)
예제를 보면서 마무리하자.