노션으로 다시 돌아갔습니다 😅

오버라이딩(overriding), super, super() (feat. this, this())

by mignon25
오늘 배운 것을 나에게 설명해주기.

오버라이딩이란?

상위 클래스로부터 상속받은 메서드의 내용을 변경하는 것

 

오버라이딩을하는 이유

상속받은 메서드를 그대로 사용하기도 하지만, 하위 클래스 자신에 맞게 변경해야 하는 경우가 있다.

다음 예시를 보자.

class Point {
    int x;
    int y;
    
    String getLocation() {
        return String.format("x: %d, y: %d", x, y);
    }
}

class Point3D extends Point {
    int z;
    
    String getLocation() {
        return ?
    }
}

상위 클래스는 2차원의 좌표만 가지지만 하위 클래스인 Point3D는 3차원 좌표를 가지고 있다.

오버로딩하거나 새로운 메서드를 추가하는 방법도 있겠지만 그것보다는,

getLocation()을 호출하면 상위 클래스인 Point 의 getLocation()이 그랬듯이 

Point3D에서도 점의 좌표를 문자열로 얻을 수 있을 것이라고 기대하는 것이 좀 더 직관적이다.

(코드가 추가된다는 비효율적인 측면도 있고)

그러므로 하위 클래스의 상황에 맞게 메서드의 내용을 변경(오버라이딩)하는 것이다. 

 

오버라이딩이 성립하기 위한 조건

1. 메서드의 선언부(메서드 이름, 매개변수, 반환타입)이 상위클래스의 그것과 완전히 일치해야 한다. 
2. 접근 제어자의 범위가 상위 클래스의 메서드보다 같거나 넓어야 한다. 
3. 예외는 상위 클래스의 메서드보다 많이 선언할 수 없다. 

참고 : JDK1.5부터 공변 반환타입(covariant return type)이 추가되어 반환타입을 자손 클래스의 타입으로 변경하는 것은 가능하도록 조건이 완화되었다.)

 

오버로딩 vs 오버라이딩

오버로딩(overloading) 기존에 없는 새로운 메서드를 정의하는 것(new)
오버라이딩(overriding) 상속받은 메서드의 내용을 변경하는 것(change, modify)

오버로딩은 한 클래스 내에 이름이 같고 나머지 시그니처(매개변수의 타입이나 개수)가 다른 메서드를 여러 개 정의하는 것이고, 오버라이딩은 부모로부터 상속받은 같은 이름의 메서드의 내용만 변경하는 것.


super

상위 클래스의 객체를 가리키는 참조 변수

하위 클래스에서 상위 클래스로부터 상속받은 멤버를 참조하는데 사용된다.

 

cf. this와 this()

this

자기 객체를 가리키는 참조 변수

메서드 내에서 멤버 변수와 지역 변수의 이름이 같을 때 구분하기 위한 용도로 사용.

생략 시 컴파일러가 자동 추가.

this()

같은 클래스의 다른 생성자 호출(자신의 생성자 호출)

 

super 와 this

상속받은 멤버와 자신의 멤버의 이름이 같을 때 super와 this로 구별할 수 있다.

(동일한 이름으로 상위 클래스에서도 선언하고 하위 클래스에서도 각자 선언한 경우)

중복이 아닌 경우에는 super와 this가 가리키는 값은 동일하다.

모든 인스턴스메서드에는 자신이 속한 인스턴스의 주소가 지역변수로 저장되는데, 이것이 참조변수인 this와 super의 값이 되기 때문.

더보기
class SuperClass {
    int count = 20; // super.count
    String name = "I am SuperClass";  // 상위 클래스에서만 정의됨
}

class SubClass extends SuperClass {
    int count = 15; // this.count

    void callNum() {
        System.out.println("count = " + count);
        System.out.println("this.count = " + this.count);
        System.out.println("super.count = " + super.count);
    }
    void callName() {
        System.out.println("name = " + name);
        System.out.println("this.name = " + this.name);
        System.out.println("super.name = " + super.name);
    }
}

public class Test {
    public static void main(String[] args) {
        SubClass sc = new SubClass();
        sc.callNum();
        System.out.println();
        sc.callName();
    }
}

// 출력 결과
count = 15
this.count = 15
super.count = 20

name = I am SuperClass
this.name = I am SuperClass
super.name = I am SuperClass

 

super()

상위 클래스의 생성자를 호출하는 것.

하위 클래스가 인스턴스를 생성하면 하위 클래스의 멤버와 상위 클래스의 멤버가 모두 합쳐진 하나의 인스턴스가 생성되는데, 이 때 상위 클래스 멤버를 초기화하기 위해 상위 클래스의 생성자가 호출되어야 한다. 

 

super() 와 this() 에서 기억해두어야 할 중요한 사실

생성자 안에서만 사용 가능하고, 반드시 첫 줄에 와야 한다. 
모든 생성자의 첫 줄에는 반드시 this() 또는 super()가 선언되어야 한다.

Object를 제외한 모든 클래스의 생성자는 첫 줄에 반드시 자신의 다른 생성자 또는 상위 클래스의 생성자를 호출해야 한다. 그래서 생성자에 super()나 this()가 없는 경우 컴파일러는 생성자의 첫줄에 super(); 를 자동으로 추가한다.

 

그런데 이 때 주의할 점이 또 있다. (애정하는 내 키보드들...)

class Keyboard {
    String switchKind;
    Keyboard(String switchKind) {
        this.switchKind = switchKind;
    }
}

class NuphyAir extends Keyboard {
    int keyNumber;
    public NuphyAir(String switchKind, int keyNumber) {
        this.switchKind = switchKind;
        this.keyNumber = keyNumber;
    }
}
// 컴파일 에러 발생

지금 하위 클래스에서 아무런 생성자를 사용하고 있지 않다.

이 경우 컴파일러가 생성자의 첫줄에 자동으로 super(); 를 추가한다. 

추가된 super()는 상위 클래스의 기본 생성자인 Keyboard()를 호출하는데, 

문제는 상위 클래스에 기본 생성자인 Keyboard()가 없다는 것.

그래서 컴파일 에러가 발생하는데, 해결방법은

1. 상위 클래스에 Keyboard() 라는 기본 생성자를 추가하거나,

2. 하위 클래스의 생성자 첫 줄에 상위 클래스 생성자 형식에 맞게 super(switchKind) 를 추가해주면 된다. 

class Keyboard {
    String switchKind;

    Keyboard(String switchKind) {
        this.switchKind = switchKind;
    }
    // Keyboard(){} - 1번
}

class NuphyAir extends Keyboard {
    int keyNumber;
    public NuphyAir(String switchKind, int keyNumber) {
        // super(switchKind); - 2번
        this.switchKind = switchKind; // 2번 사용 시 이 줄 삭제
        this.keyNumber = keyNumber;
    }
}

 

결론.

기본 생성자를 생성하는 것을 습관화하자.

 

블로그의 정보

Mignon'S Dev Log

mignon25

활동하기