20260403FRI (DAY 7)

sungsimdangmascot·2026년 4월 3일

1. 상속

정의

상속이란 부모 클래스(상위 클래스)가 가진 속성(변수)과 기능(메서드)을 자식 클래스(하위 클래스)가 물려받는 것을 의미한다. 현실 세계에서 부모의 재산을 자식이 물려받는 것과 유사한 개념이다.

목적: 중복 제거와 유지보수

상속을 사용하는 가장 큰 이유는 코드의 중복을 제거하기 위함이다.

  • 문제 상황: 만약 전사, 마법사, 도적이라는 3개의 캐릭터 클래스가 있다고 가정하자. 상속이 없다면 각 클래스마다 걷기(), 먹기(), 자기()와 같은 공통 기능을 매번 따로 작성해야 한다.

  • 유지보수의 어려움: 캐릭터가 100개로 늘어난 상황에서 걷기() 기능을 수정해야 한다면, 100개의 클래스를 일일이 찾아가서 수정해야 하는 재앙이 발생한다.

  • 해결책: 공통 기능을 부모 클래스(캐릭터)에 단 한 번만 정의하고 이를 상속받으면, 부모 클래스의 코드만 수정해도 모든 자식 클래스에 즉시 반영된다.


2. 상속의 구현: extends 키워드

자바에서는 extends 키워드를 사용하여 상속을 표현한다. 자식 클래스는 부모 클래스의 기능을 확장한다는 의미를 담고 있다.

class 캐릭터 {
    int attackPoint;
    int defensePoint;

    void 걷기() {
        System.out.println("걷기");
    }

    void 뛴다() {
        System.out.println("뛴다");
    }
}

// 전사는 캐릭터를 상속받는다.
class 전사 extends 캐릭터 {
    // 걷기(), 뛴다()는 보이지 않아도 이미 포함되어 있다.
    void 칼을_휘두른다() {
        System.out.println("칼 휘두르기");
    }
}

전사 클래스 내부에는 걷기()뛴다()가 적혀 있지 않지만, extends 캐릭터 덕분에 전사 객체는 해당 기능을 공짜로 얻어 사용하게 된다.


3. 상속의 조건: IS-A 관계

상속은 단순히 코드를 복사하기 위해 사용하는 도구가 아니다.
반드시 "자식은 부모의 한 종류이다"라는 IS-A 관계가 성립해야 한다.

  • 성립하는 경우: 전사는 캐릭터이다(Warrior IS-A Character), 마법사는 캐릭터이다.
  • 성립하지 않는 경우: 자동차는 캐릭터이다. (이런 경우 상속을 사용해서는 안 되며, 전혀 다른 종류의 클래스로 분리해야 한다.)

관계가 명확하지 않은 무분별한 상속은 오히려 프로그램의 구조를 복잡하게 만들고 논리적 오류를 범하게 한다.


4. 상속의 주요 특징 및 보강 개념

단일 상속 (Single Inheritance)

자바는 클래스 간의 단일 상속만을 허용한다. 즉, 하나의 자식 클래스는 오직 하나의 부모 클래스만을 가질 수 있다. 여러 부모로부터 상속받을 때 발생할 수 있는 충돌(다이아몬드 문제)을 방지하기 위함이다.

메서드 오버라이딩 (Method Overriding)

부모에게 물려받은 기능이 자식에게 맞지 않을 경우, 자식 클래스에서 해당 기능을 재정의할 수 있다. 예를 들어, 캐릭터걷기()가 일반적인 걸음이라면 전사무거운 걸음으로 걷기()로 내용을 바꿀 수 있다.

모든 클래스의 조상: Object 클래스

자바에서 상속을 명시하지 않은 모든 클래스는 자동으로 java.lang.Object 클래스를 상속받는다. 따라서 모든 자바 객체는 Object가 가진 기본 기능(toString, equals 등)을 사용할 수 있다.


1. 상속의 정의

부모가 가진 재산을 자식이 물려받는 것과 같다.

  • 부모 클래스(상위 클래스): 공통 기능을 모아둔 설계도 (예: 캐릭터)
  • 자식 클래스(하위 클래스): 부모의 기능을 물려받고, 자신만의 기능을 추가한 설계도 (예: 전사, 마법사, 도적)

2. 상속을 사용하는 이유: 중복 제거

상속이 없다면 전사, 마법사, 도적을 만들 때마다 똑같은 걷기(), 빠르게_뛴다(), 하늘을_날다()와 같은 속성과 기능을 매번 새로 써줘야 한다.

  • 문제: 캐릭터가 100개일 때 걷기() 기능을 수정해야 한다면 100번 고쳐야 한다.
  • 해결: 각 캐릭터의 공통적인 기능을 모아둔 부모 클래스를 만들고 모두가 상속받게 한다. 부모 클래스의 걷기()만 수정하면 모든 자식에게 적용된다.

3. 상속의 한계와 문제점

상속은 부모의 모든 것을 강제로 물려받기 때문에 "A는 B이다"가 완벽하게 성립하지 않으면 부작용이 발생한다.

① 원치 않는 기능의 전수

  • 상황: 로봇오리가 고무오리를 상속받음.
  • 문제: 고무오리가 "날 수 없음"을 정의하면 로봇오리도 자동으로 날지 못하게 된다. 나중에 "하늘을 나는 로봇오리"를 만들려면 부모의 기능을 강제로 뜯어고치는(오버라이딩) 수고를 해야 한다.

② 중복 코드의 재발 (상속 계층의 꼬임)

  • 상황: 로봇오리는 고무오리 계열이지만, 수영은 일반 오리처럼 '물갈퀴'로 하고 싶어 한다.
  • 문제: 자바는 단일 상속만 가능하므로 로봇오리는 이미 고무오리를 상속받고 있어 일반 오리의 수영 기능을 가져올 방법이 없다.
  • 결과: 결국 로봇오리 안에 일반 오리와 똑같은 "물갈퀴로 헤엄칩니다"라는 코드를 직접 중복해서 써야 한다.

③ 강한 결합과 유지보수의 어려움

  • 실행 중 변경 불가: 게임 중에 고무오리가 아이템을 먹어 로봇오리로 변신해야 한다면, 상속 구조에서는 객체를 아예 새로 만들어야 한다.
  • 파급 효과: 부모 클래스를 수정하면 그 아래에 매달린 수많은 자식 클래스들이 의도치 않게 오작동할 위험이 커진다.

4. 상속 지옥(Inheritance Hell)

종류가 계속 추가될수록 다음과 같은 현상이 발생한다.

  • 부모를 누구로 정할지 매번 고민하게 된다.
  • 여기저기서 똑같은 코드를 복사해서 오버라이딩하게 된다.
  • "헤엄칩니다"를 "수영합니다"로 바꾸고 싶을 때 어떤 클래스를 고쳐야 할지 몰라 헤매게 된다.

5. 최종 결론

  • 강한 결합: 부모가 변하면 자식이 원치 않아도 영향을 받는다.
  • 코드 중복 재발: 계층이 꼬이면 서로 다른 부모를 둔 자식들 사이에 중복 코드가 생긴다.
  • 수정의 어려움: 계층이 깊어질수록 중간 단계를 수정하기가 어려워진다.
  • 단일 상속의 한계: 여러 부모의 장점을 섞기 힘들다.


1. 수동 형변환의 정의

수동 형변환이란 개발자가 명시적으로 타입을 지정하여 강제로 형변환을 수행하는 것을 의미한다. 주로 큰 데이터 타입을 작은 데이터 타입에 대입하거나, 객체지향 프로그래밍에서 부모 타입을 자식 타입으로 변환(Downcasting)할 때 사용한다.


2. 객체 수동 형변환이 필요한 이유

리모컨 버튼의 제한

자바에서 동물 a원숭이 = new 원숭이();와 같이 선언하면, 변수 a원숭이는 '동물' 타입의 리모컨이 된다. 실제 객체가 '원숭이'라 할지라도, 리모컨이 '동물' 규격이기 때문에 동물 클래스에 정의되지 않은 원숭이만의 고유 기능(예: 묘기부리다)은 호출할 수 없다.

기능의 복구 (Downcasting)

자식 객체만이 가진 특수한 기능을 다시 사용하기 위해서는, 부모 타입으로 좁혀졌던 리모컨을 다시 자식 타입으로 확장해야 한다. 이때 수동 형변환을 통해 "이 객체는 사실 원숭이가 맞다"라고 자바에게 알려줌으로써 숨겨졌던 버튼(메서드)을 되살린다.


3. 수동 형변환의 메커니즘

자바는 부모 타입을 자식 타입으로 변환하는 것을 자동으로 허용하지 않는다. 부모는 자식보다 큰 개념이므로, "동물은 원숭이다"라는 명제가 항상 참이 아닐 수 있기 때문이다. 따라서 개발자가 직접 괄호를 사용하여 책임을 명시해야 한다.

동물 a동물 = new 원숭이(); // 자동 형변환 (Upcasting)
// a동물.묘기부리다(); // 컴파일 에러: 동물 리모컨에는 묘기 버튼이 없음

원숭이 a원숭이 = (원숭이)a동물; // 수동 형변환 (Downcasting)
a원숭이.묘기부리다(); // 성공: 원숭이 리모컨으로 교체되어 버튼이 생김

4. 주의사항 및 위험성

ClassCastException 예외

수동 형변환은 개발자가 자바의 안전 장치를 해제하고 강제로 진행하는 작업이다. 만약 실제 객체가 '토끼'인데 강제로 '원숭이'로 형변환을 시도할 경우, 컴파일 단계에서는 문제가 없으나 프로그램 실행 도중 ClassCastException이 발생하며 강제 종료된다.

instanceof 연산자 활용

이러한 위험을 방지하기 위해, 수동 형변환 전에는 반드시 instanceof 연산자를 사용하여 객체의 실제 타입을 확인하는 것이 안전하다.


5. 요약 및 결론

  • 자동 형변환: 자식에서 부모로 가는 것. 안전하며 버튼이 줄어든다.
  • 수동 형변환: 부모에서 자식으로 가는 것. 위험하며 잃어버린 버튼을 되찾기 위해 사용한다.
  • 핵심: 모든 객체를 공통적으로 다룰 때는 부모 타입을 쓰고, 특정 객체만의 필살기가 필요할 때만 수동 형변환을 통해 자식 타입으로 꺼내어 사용한다.
profile
성심당마스코트

0개의 댓글