AiPE

객체지향에서의 상속(Inheritance)과 오버라이딩(Overriding) 본문

[XiBBaL] Study/Java

객체지향에서의 상속(Inheritance)과 오버라이딩(Overriding)

Oshimaker XiBBaL 2024. 4. 3. 15:43
반응형

객체지향의 핵심 개념 중의 하나인 상속(Inheritance)에 대해 알아보자.

 

 

1. 상속(Inheritance)이란?

Java에서는 하나의 클래스가 존재할 때,

이 클래스의 속성(변수와 메서드)를 다른 클래스에서 그대로 물려받아 사용할 수 있다. 

이렇게 하나의 클래스가 다른 클래스에게 자신의 속성을 물려주는 행위 자체를 상속이라고 부른다.

 

상속을 해주는 클래스를 부모 클래스, 상속을 받는 클래스를 자식 클래스라고 부른다.

부모 클래스가 더 큰 집합이므로, 자식 클래스는 부모 클래스의 모든 속성을 일단 그대로 물려받는다.

단, 자식 클래스는 부모 클래스가 가지지 못하는 속성을 추가하여 사용할 수 있다.

 

 

 

그렇다면 상속이 왜 객체지향의 핵심적인 특성이며, 코드를 효율적으로 해 주는 장치일까?

이를 알아보기 위해 프로그래머가 A, B, C, D, E라는 기능을 조합하여 기능을 구현해야 한다고 가정하자.

 

 

1.

필요할 때마다 새로운 클래스에 각각의 기능을 담아 기능을 구현하는 것도 가능하겠지만,

이렇게 하면 매번 동일한(비슷한) 코드를 작성하고 또 작성하고 해야 하기 때문에 귀찮다.

 

예를 들어, class_1과 class_2를 구현하고자 할 때, 부모 클래스가 없다면 A, B, C를 각각 두 번 쳐야 한다.

지금 예시에서는 두 번이니까 눈 딱 감고 두 번 하면 될지 몰라도, 구현해야 하는 클래스가 100개, 1000개라면 어떻게 될까? 

상속을 하지 않고서는 못 배길 것이다.

 

 

 

2. 

또, 유지 보수를 위해 코드를 수정해야 할 때에도 매 클래스마다 일일이 수정해주어야 한다는 문제가 있다.

 

예를 들어, 속성 B를 B'으로 교체해야 할 때, 부모 클래스를 설정해 놓지 않았으면 class_1과 class_2를 모두 열어서 B를 B'으로 수정해야 한다.

반면 부모 클래스가 정의되어 있으면 부모 클래스 하나만 열어서 B를 B'으로 수정하면 된다.

이를 상속받는 자식 클래스는 자동으로 변경사항이 들어가기 때문에 개별적으로 수정할 필요가 없다.

 

마찬가지로 자식 클래스가 현재의 예시에서처럼 2개가 아니라 100개, 1000개라면 어떨까?

상속을 하지 않고서는 못 배길 것이다.

 

 

 

3.

프로그래머 입장이 아닌, 컴퓨터의 입장에서도 코드의 부피가 불필요하게 늘어나는 문제가 있다.

이는 저장 공간 등의 자원을 불필요하게 소모한다.

 

 

 

프로그래머들은 이러한 귀찮은 문제를 해결하기 위해 여러 기능 중 공통되는 부분을 부모 클래스로 지정해 처리할 수 있다.

아래 그림을 보자.

 

 

클래스 1, 2, 3은 공통되는 기능을 가진다.

이 공통 부분을 부모 클래스로 지정한 후, 클래스 1, 2, 3을 부모 클래스에 대한 자식 클래스로 만들면

공통부분을 상속받아 서로 다른 부분만 구현해 사용할 수 있다.

공통부분에서 수정 사항이 발생할 때에도 클래스 1, 2, 3을 모두 일일이 수정할 필요 없이 부모 클래스만 수정해주면 된다.

 

이처럼 상속은 부모 클래스가 가지는 속성을 자식 클래스에게 그대로 물려주는 구조를 의미한다.

 

 

 

 

2. 오버라이딩(Overriding)

이제 개발자는 상속이 얼마나 중요하고 써먹었을때 유리한지에 대해 이해하고 적극적으로 상속을 이용하려고 할 것이다.

 

하지만 다음과 같은 경우가 발생할 수 있다.

부모 클래스의 기능을 상속받아 자식 클래스를 만들 때, 부모 클래스의 기능 1000개 중 999개는 마음에 들지만 1개만 마음에 들지 않으면 어떨까?

 

상속을 포기하기에는 999개의 기능을 모두 다시 구현해야 해서 시간적, 공간적 낭비가 크지만

그대로 상속받기에는 한 개의 기능 때문에 적합하지 않아 써먹을 수가 없다.

 

이러한 상황에서 상속을 포기하지 않기 위해 탄생한 개념이 바로 오버라이딩이다.

 

 

오버라이딩(Overriding)의 정의
오버라이딩은 부모 클래스에서 이미 정의된 메서드를 자식 클래스에서 다시 정의하는 것이다.

 

 

오버라이딩을 사용하면 부모 클래스에서 정의된 메서드를 자식 클래스에서 필요에 따라 수정할 수 있게 된다.

이는 자식 클래스가 부모 클래스의 동작을 재정의하여 자체적인 동작을 구현할 수 있도록 해준다.

 

만약 메서드 A를 포함하는 부모 클래스 1개와 이를 상속받는 자식 클래스 100개가 있을 때,

자식 클래스 99개는 A를 그대로 필요로 하지만 마지막 자식 클래스는 A대신 A'을 필요로 한다고 하자.

이러한 경우 일단 상속을 받고, 마지막 자식 클래스에서만 오버라이딩을 진행해 A를 A'으로 교체해 주는 것이다.

 

이를 통해 앞에서 설명한 상속의 장점을 모두 챙기면서, 정말 약간의 수정이 필요해 상속을 받지 못하는 문제를 효과적으로 해결할 수 있다.

 

오버라이딩의 경우 "@Override"라는 기호를 사용해 다음과 같이 정의한다.

class Animal {
    void makeSound() {
        System.out.println("Some sound");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Bark");
    }
}

 

 

 

 

 

참고.

비슷한 단어인 오버로딩(Overloading)은 오버라이딩과 직접적인 관계는 없다.

둘 모두 객체지향에서 다형성을 보장하기 위한 방법이라는 공통점이 있지만 이 이외에는 딱히 접점이 없다.

오버라이딩은 상속과 관련된 개념이고 오버로딩은 메소드의 이름 처리에 관한 개념이기 때문이다.

둘의 정의와 비교에 대해서는 아래 포스팅을 참고하자.

 

!-- <<링크>>

반응형