오버라이딩이란?
조상클래스로부터 상속받은 메소드의 내용을 변경하는 것을 오버라이딩이라고 한다.
상속받은 메소드를 그래도 사용하기도 하지만, 자손 클래스 자신에 맞게 변경해야하는 경우가 많다.
이럴 때 조상의 메소드를 오버라이딩한다.
다음 코드를 한번 봐보자.
class Point{
int x;
int y;
String getLocation() {
return "x :" +x+", y :"+ y;
}
}
class Point3D extends Point{
int z;
String getLocation() { //오버라이딩
return "x :" +x+", y :"+ y + ", z :"+ z;
}
}
이 두 클래스는 서로 상속관계에 있으므로 Point3D클래스는 Point클래스로부터 getLocation()을 상속받았지만,
Point3D클래스는 3차원 좌표계의 한 점을 표현하기 위한 것이므로
조상인 Point클래스로부터 상속받은 getLocation()은 Point3D클래스에 맞지 않는다.
그래서 이 메소드를 Point3D클래스 자신에 맞게 z축의 좌표값도 포함하여 반환하도록 오버라이딩하였다.
오버라이딩의 조건
오버라이딩은 메소드의 내용만을 새로 작성하는 것이므로 메소드의 선언부는 조상의 것과 완전히 일치해야한다.
또한 다음과 같은 조건을 지켜야한다.
자손 클래스에서 오버라이딩하는 메소드는 조상 클래스의 메소드와
1. 이름이 같아야 한다.
2. 매개변수가 같아야 한다.
3. 반환타입이 같아야 한다.
또한
조상 클래스의 메소드를 자손 클래스에서 오버라이딩할 때
1. 접근 제어자를 조상 클래스의 메소드보다 좁은 범위로 변경할 수 없다.
접근제어자의 접근 범위를 넓은 것에서 좁은 것 순을 나열한다면
public, protexted, (default), private이다.
2. 예외는 조상 클래스의 메소드보다 많이 선언할 수 없다.
3. 인스턴스 메소드를 static메소드로 또는 그 반대로 변경할 수 없다.
오버로딩 vs 오버라이딩
오버로딩은 기존에 없는 새로운 메소드를 추가하는 것이고,
오버라이딩은 조상으로부터 상속받은 메소드의 내용을 변경하는 것이다.
class Parent{
void parentMethod() { }
}
class Child extends Parent{
void parentMethod() { } //오버라이딩
void parentMethod(int i) { } //오버로딩
}
super
super는 자손 클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수이다.
멤버변수와 지역변수의 이름이 같을 때 this를 붙여서 구별했듯이
상속받은 멤버와 자신의 멤버와 이름이 같을 때는 super를 붙여서 구별할 수 있다.
조상클래스로부터 상속받은 멤버도 자손 클래스 자신의 멤버이므로 super대신 this를 사용할 수 있다.
그래도 조상 클래스의 멤버와 자손클래스의 멤버가 중복 정의되어 서로 구별해야하는 경우에만
super를 사용하는 것이 좋다.
다음 예시를 살펴보자.
위의 예시를 보면 알 수 있듯이,
상속받은 멤버도 자손 클래스 자신의 멤버이므로 this를 사용하여 x를 호출할 수 있다.
또한, super를 통해 상속받은 멤버를 참조하는데 사용하여 호출할 수 있다.
하지만 이럴 때는 this를 사용하는 것이 좋고,
다음과 같이 조상과 자손클래스의 멤버가 중복 정의되어 서로 구별해야하는 경우에만 super를 사용하는 것이 좋다.
위의 예시와 같이 상속받았다고 가정해보자.
이 경우에는 super.x와 this.x는 서로 다른 값을 참조하게된다.
super.x는 조상 클래스로부터 상속받은 멤버변수 x를 뜻하며,
this.x는 자손 클래스에 선언된 멤버변수를 뜻한다.
변수만이 아니라 메소드 역시 super를 써서 호출할 수 있다.
특히 조상클래스의 메소드를 자손클래스에서 오버라이딩한 경우에 super를 사용한다.
다음 예시를 살펴보자.
class Point{
int x;
int y;
String getLocation() {
return "x :" +x+", y :"+ y;
}
}
class Point3D extends Point{
int z;
String getLocation() { //오버라이딩
//return "x :" +x+", y :"+ y + ", z :"+ z;
return super.getLocation() + ", z :"+ z; //조상의 메소드 호출
}
}
조상클래스의 메소드의 내용을 추가적으로 작업을 덧붙이는 경우라면
이처럼 super를 사용해서 조상클래스의 메소드를 포함시키는 것이 좋다.
후에 조상클래스의 메소드가 변경되더라도 변경된 내용이 자손클래스의 메소드에 자동적으로 반영될 것이기 때문이다.
super() - 조상 클래스의 생성자
this()와 마찬가지로 super() 역시 생성자이다. this()는 같은 클래스의 다른 생성자를 호출하는데 사용되지만,
super()는 조상 클래스의 생성자를 호출하는데 사용된다.
자손클래스의 인스턴스를 생성하면, 자손의 멤버와 조상의 멤버가 모두 합쳐진 하나의 인스턴스가 생성된다.
그래서 자손 클래스의 인스턴스가 조상 클래스의 멤버들을 사용할 수 있는 것이다.
이 때 조상 클래스 멤버의 초기화 작업이 수행되어야 하기 때문에
자손 클래스의 생성자에서 조상 클래스의 생성자가 호출되어야 한다.
생성자의 첫 줄에서 조상 클래스의 생성자를 호출해야하는 이유는 자손 클래스의 멤버가 조상 클래스의 멤버를 사용할 수도 있으므로 조상의 멤버들이 먼저 초기화 되어야 하기 때문이다.
이와 같은 조상 클래스 생성자의 호출은 클래스의 상속관계를 거슬러 올라가면서 계속 반복된다.
마지막으로 모든 클래스의 최고 조상인 Object클래스의 생성자인 Object() 까지 가서야 끝이 난다.
그래서 Object클래스를 제외한 모든클래스의 생성자는
첫 줄에 자신의 다른 생성자 또는 조상의 생성자를 호출해야 한다.
만일 그렇지 않으면 컴파일러가 자동적으로 super();를 추가할 것이다.
다음 예시를 살펴보자.
Point3D클래스의 생성자에서 조상 클래스의 생성자인 Point()를 찾을 수 없다는 에러가 발생하였다.
Point3D클래스의 생성자를 보면 첫 줄이 생성자(조상의 것이든 자신의 것이든)를 호출하는
문장이 아니기 때문에 컴파일러는 super()를 자동적으로 생성자의 첫줄에 넣어주었다.
super()는 Point3D클래스의 조상인 Point클래스의 기본 생성자인 Point()를 뜻하므로 Point()가 호출된다.
그러나 Point클래스에 새성자 Point()가 정의되어 있지 않기 때문에
Point클래스에 Point()를 추가해주던가, Point3D생성자 첫줄에 Point(int x, int y)를 호출하도록 변경하면된다.
따라서 Point3D생성자를 다음과 같이 변경해주면 된다.
Point3D(int x, int y, int z){
super(x, y); //조상클래스의 생성자 Point(int x, int y)를 호출한다.
this.z = z;
}
조상 클래스의 멤버변수는 이처럼 조상의 생성자에 의해 초기화되도록 해야 하는 것이다.
위의 예시를 수정한 프로그램을 살펴보자.
먼저 Point클래스부터 보자면, 생성자 첫 줄에서 다른 생성자를 호출하지 않기 때문에
컴파일러가 super()를 첫 줄에 삽입한다.
super()는 Point의 조상인 Object클래스의 기본 생성자인 Object()를 의미한다.
Point3D클래스에서 super(x, y)를 통해 Point클래스의 Point(int x, int y)를 호출하여
조상의 생성자에 의해서 초기화를 하였다.
생성자가 호출되는 순서는 다음과 같다.
Point3D() -> Point3D(int x, int y, int z) -> Point(int x, int y) ->Object()
어떤 클래스의 인스턴스를 생성하면, 클래스의 상속관계의 최고조상인 Object클래스까지
거슬러 올라가면서 모든 조상클래스의 생성자가 순서대로 호출된다는 것을 알 수 있다.
'JAVA > Basic' 카테고리의 다른 글
[JAVA-basic] 다형성 (0) | 2021.08.24 |
---|---|
[JAVA-basic] 제어자 (0) | 2021.08.20 |
[JAVA-basic] 상속(2) (0) | 2021.08.18 |
[JAVA-basic] 상속 (0) | 2021.08.18 |
[JAVA-basic] 변수의 초기화 (0) | 2021.08.15 |