본문 바로가기
Programming/Java

[Java] 10. 상속 (Inheritance)

by Rayched 2022. 12. 22.

1. 상속 (Inheritance)

① 상속의 정의

상속의 사전적인 정의는 "부모가 가진 것을 자식에게 물려주는 것."이라고 할 수 있다.

프로그래밍에서의 상속도 이러한 기능을 가지고 있다.상속은 객체 지향 프로그래밍에서 제공되는 함수/데이터 모듈화의 일종으로피상속 객체의 데이터나 함수를 상속 객체가 그대로 이어받아서 쓸수 있는 기능이다.

여기서 데이터와 함수를 이어주는 피상속 객체를 '부모 클래스'

이를 상속받는 상속 객체를 '자식 클래스'라고 한다.


② 상속 사용 방법

프로그래밍에서 상속 기능을 사용하는 방법은 아래와 같다.

class 동물 {

}

class 사람 extends 동물 {

}
//class <자식 클래스 명1> extends <부모 클래스 명2>
//부모 클래스: 동물
//자식 클래스: 사람
//사람 class는 동물 class의 자식 클래스로
//동물이 가진 능력을 상속받는다.

부모 클래스로부터 상속받은 자식 클래스는

부모 클래스가 가진 능력(변수, 함수)를 모두 사용할 수 있으며

자식 클래스는 부모 클래스로 부터 물려받은 능력 외에도

자신만의 변수, 함수를 가지는 것이 가능하다.

단, 부모 클래스는 자식 클래스에서 추가된 변수나 함수를 가지는 것이 불가능하다.

 

이것 외에도 자식 클래스는 부모 클래스로 부터 물려받은 메소드를 재정의할 수 있다.

이를 '오버라이딩(Overriding)'이라고 한다.

다음 소스코드는 부모 클래스에서 정의한 메소드를

자식 클래스에서 오버라이딩한 예시이다.

public class Main {
  public static void main(String[] args){
    사람 a사람 = new 사람();
    a사람.숨쉬다();
  }
}

class 동물 {
  void 숨쉬다(){
    System.out.println("숨을 쉽니다.");
  }
}

class 사람 extends 동물 {
//부모 클래스 동물이 가진 메소드를 재정의(overriding)
  void 숨쉬다(){
    //super.숨쉬다(); (부모 클래스의 메소드 호출)
    //'super' 키워드를 사용하면
    //부모 클래스의 메소드(오버라이딩 X)를 호출할 수 있다.
    System.out.println("사람이 숨을 쉽니다.");
  }
}

 

메서드 오버라이딩 조건

  • 메서드의 동작만을 재정의하기 때문에 메소드의 선언부는 기존 메서드와 같아야한다.
  • 자식 클래스에서 오버라이드한 메서드의 접근 제어자는 부모의 메서드보다 더 좁은 범위로 변경해서는 안된다.

         (자식 클래스에서 오버라이드한 메서드의 접근 제어자 범위 >= 부모 클래스 원본 메서드 접근 제어자 범위)

         (부모 메서드의 접근 제어자가 public이면 자식의 메서드의 범위도 public이어야한다.)


③ 다중 상속에 대하여

다중 상속의 정의에 대해 말하기 전에 알고 넘어가야할 것이 있다.

자바에서는 기본적으로 자식 클래스가 여러 개의 부모 클래스를 갖는 다중 상속을 지원하지 않는다.

다중 상속을 지원하지 않는 이유에 대해 알아보기 위해서 예제를 하나 준비했다.

//오리 시뮬레이터
//1. 로봇오리를 추가해주세요. 그리고 로봇오리는 날기, 수영이 가능해야 합니다.

public class Main {
    public static void main(String[] args) {
        오리 a오리 = new 오리();
        청둥오리 a청둥오리 = new 청둥오리();
        a청둥오리.날기();
        고무오리 a고무오리 = new 고무오리();
        a고무오리.날기();

        //로봇오리 생성
        로봇오리 a로봇오리 = new 로봇오리();

    }
}

class 오리 {
    void 날기() {}
}

class 청둥오리 extends 오리 {
    @Override
    void 날기() {
        System.out.println("오리가 날개로 날아갑니다.");
    }
}

class 고무오리 extends 오리 {
    @Override
    void 날기() {
        System.out.println("오리가 물갈퀴로 수영합니다.");
    }
}

//로봇오리 클래스를 만들고 청둥오리와 고무오리의 원본 메서드를 실행
class 로봇오리 extends 청둥오리, 고무오리 {
    @Override
    void 날기() {
        super.날기(); //부모 클래스의 원본 메소드를 실행시키는 키워드
    }
}

 

오리 클래스가 '날기()'라는 메소드를 가지고 있고

청둥오리와 고무오리가 '날기()' 메소드를 오버라이딩해서

오리가 날개로 날거나, 물갈퀴로 수영하도록 구현을 했다.

 

이제 로봇오리가 이 두 능력을 상속받을 차례이다.

로봇오리가 청둥오리, 고무오리와 상속 관계가 되게 한 다음

프로그램을 실행하기 위해 컴파일을 실행해보지만

컴파일은 되지 않는다.

 

아래의 그림은 오리와 상속받은 하위 클래스 간의 관계를 표현한 그림이다.

 

오리 시뮬레이터 다이어그램

제시된 문제를 살펴보면 로봇오리는 날기와 수영 모두 가능해야 한다고 한다.

그러므로 청둥오리의 날기 메소드와 고무오리의 날기 메소드를 동시에 가져야하므로

청둥오리, 고무오리와 상속 관계가 되게 해보자.

 

로봇오리는 날기 메소드를 상속받았지만

해당 메소드는 실행되지 못한다.

왜냐하면 부모 클래스인 청둥오리와 고무오리 양 쪽에 모두 정의된 상태이고

날기를 하게하려면 청둥오리로 부터 상속받은 메소드를 실행하면 되지만

이러면 고무오리로 부터 물려받은 메소드와 충돌이 생긴다.

반대로 수영을 하려면 고무오리로 부터 받은 메소드를 실행하면 되지만

청둥오리로 부터 상속받은 메소드와 충돌이 생긴다.

즉, 로봇오리 입장에서는 어떤 메소드를 실행해야 하는 지를 판단할 수가 없는 상황이 된거다.

이런 식으로 복잡한 상속으로 발생하게되는 문제를 '다이아몬드 문제'라고 한다.

 

물론, 자바에서는 이런 문제가 발생하지 않도록

내부적으로 다중 상속이 불가능하도록 제한을 걸어둔 상태이기 때문에

해당 소스코드가 컴파일이 되지 않는 것은 당연한 일이다.

 

 

 

 

'Programming > Java' 카테고리의 다른 글

[Java] 12. 캡슐화와 접근 제어자  (0) 2023.01.16
[Java] 11. 생성자 (Constructor)  (0) 2023.01.16
[Java] 9. static  (0) 2022.12.21
[Java] 8. Scanner  (0) 2022.12.04
[Java] 함수, 메소드  (0) 2022.11.30