7.6 super 키워드와 super() (The 'super' Keyword)
자식 클래스가 부모 클래스로부터 상속을 받게 되면 부모의 멤버 변수와 메서드를 사용할 수 있습니다. 그러나 때로는 자식 클래스와 부모 클래스의 멤버 이름이 완전히 같아서 충돌하거나, 부모의 메서드를 오버라이딩(Overriding)한 뒤에도 원래 부모의 원본 메서드를 호출 해야 할 필요가 있습니다. 이때 super 키워드를 사용합니다.
1. 참조변수 super
super는 상속받은 자식 클래스 내부에서 부모 클래스의 멤버에 접근할 때 사용하는 참조변수 입니다. 이전 장에서 배운 this가 '자기 자신'을 가리킨다면, super는 '나를 낳아준 부모'를 가리킵니다.
부모 변수와의 충돌 해결
자식 클래스의 지역 변수와 부모 클래스의 멤버 변수 이름이 같을 때, 혹은 부모에서 물려받은 변수와 자식 클래스의 변수가 같을 때 구분 목적으로 사용됩니다.
class Parent {
int x = 10;
}
class Child extends Parent {
int x = 20;
void method() {
System.out.println("x=" + x); // 자식 클래스의 안에서 가장 가까운 변수 (20)
System.out.println("this.x=" + this.x); // 자식 자신의 인스턴스 멤버 변수 (20)
System.out.println("super.x=" + super.x); // 부모로부터 상속받은 멤버 변수 (10)
}
}
부모 메서드 원본 호출
자식이 부모의 메서드를 오버라이딩하여 내용을 바꿨지만, 그럼에도 불구하고 부모의 원래 로직을 덧붙여서 재사용하고 싶을 때 매우 유용합니다. 이렇게 하면 코드가 중복되는 것을 방지합니다.
class Point3D extends Point {
int z;
@Override
String getLocation() { // 오버라이딩
// 부모(Point)의 원본 로직을 먼저 호출한 후 자식 고유의 속성을 이어붙임
return super.getLocation() + ", z :" + z;
}
}
2. 부모 생성자 호출 super()
자식 클래스의 인스턴스를 생성할 때는, 자식 공간 내부에 항상 부모 클래스의 영역부터 먼저 할당 되어야 부모의 속성들을 온전히 상속받아 사용할 수 있습니다. 이를 보장하기 위해 자바 컴파일러는 super()라는 특별한 생성자 호출 명령어를 제공합니다.
- 원칙: 자식 클래스의 모든 생성자 ** 첫 줄**에는 반드시 자기 자신의 다른 생성자
this()나 부모의 생성자super()를 호출해야 합니다. - 자동생성: 만약 개발자가 위 원칙을 어기고 아무것도 쓰지 않았다면, 컴파일러가 알아서 첫 줄에 텅 빈
super();를 자동으로 넣어줍니다.
class Point {
int x, y;
// 만약 아래처럼 매개변수가 있는 부모 생성자만 존재한다면?
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
class Point3D extends Point {
int z;
Point3D() {
// 컴파일러가 첫 줄에 무조건 super()를 넣으려 시도하지만,
// 부모엔 매개변수가 없는 기본 생성자가 없으므로 에러 발생!
} // 컴파일 에러 예시
Point3D(int x, int y, int z) {
super(x, y); // 자식 생성자의 첫 줄에서 명시적으로 부모의 원본 생성자를 호출해야 에러 해결!
this.z = z; // 남은 자식 고유의 변수는 자기 자신 this로 세팅
}
}
요약
super: 자식 안에서 부모를 가리키는 참조 변수. 부모 원본 메서드나 변수에 강제로 접근할 때 쓴다.super(): 부모의 생성자를 호출하는 명령어. 자식 인스턴스 생성 시 무조건 가장 먼저 부모를 초기화하기 위해 첫 줄에 의무적으로 써야 한다.