상속

hoon·2025년 1월 13일

JAVA

목록 보기
7/21

상속(Inheritance)

상속은 객체지향 프로그래밍(OOP)의 핵심 개념 중 하나로, 기존 클래스(부모 클래스 또는 상위 클래스)의 속성과 메서드를 새로운 클래스(자식 클래스 또는 하위 클래스)가 물려받아 재사용하거나 확장할 수 있도록 하는 기능이다. 이를 통해 코드의 재사용성과 확장성을 높이고, 프로그램 구조를 체계적으로 설계할 수 있다.


1. 상속의 개념과 필요성

상속이란 무엇인가?

  • 상속은 부모 클래스의 필드와 메서드를 자식 클래스에서 물려받아 사용하는 개념이다.
  • 자식 클래스는 부모 클래스의 기능을 그대로 사용하거나, 이를 확장하거나 재정의할 수 있다.

상속이 필요한 이유

  1. 코드 재사용: 부모 클래스에 작성된 공통 로직을 자식 클래스에서 반복 없이 활용 가능.
  2. 확장 가능성: 기존 클래스를 기반으로 새로운 기능 추가 및 수정 가능.
  3. 유지보수 용이: 공통 코드를 부모 클래스에 모아 관리하여 유지보수를 간소화.
  4. 계층적 설계: 클래스 간 관계를 계층적으로 설계하여 구조적이고 논리적인 프로그램 작성.

2. 상속의 문법

Java에서 상속은 extends 키워드를 사용하여 구현한다.

class 부모클래스 {
    // 부모 클래스의 필드와 메서드
}

class 자식클래스 extends 부모클래스 {
    // 자식 클래스의 새로운 필드와 메서드 추가 가능
}

예제

class Animal {
    String name;

    void eat() {
        System.out.println(name + " is eating.");
    }
}

class Dog extends Animal {
    void bark() {
        System.out.println(name + " is barking.");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "Buddy";
        dog.eat();  // 부모 클래스의 메서드 호출
        dog.bark(); // 자식 클래스의 메서드 호출
    }
}

3. 다형성(Polymorphism)

다형성의 의미

다형성은 하나의 참조 변수로 여러 가지 타입의 객체를 참조할 수 있는 성질이다.

즉, 부모 클래스 타입의 참조 변수를 사용하여 자식 클래스 객체를 참조할 수 있다.

Animal animal = new Dog(); // 부모 타입 참조 변수로 자식 객체 참조

다형성의 작동 원리

  1. 참조 변수의 타입은 사용할 수 있는 메서드의 범위를 결정한다.
  2. 실제 객체의 타입오버라이딩된 메서드의 실행 결과를 결정한다.

예제

class Animal {
    void sound() {
        System.out.println("Animal makes a sound");
    }
}

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

    void bark() {
        System.out.println("Dog-specific bark");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.sound(); // "Dog barks" 출력 (오버라이딩된 메서드 호출)

        // animal.bark(); // 컴파일 에러: 부모 타입에 없는 메서드
    }
}

출력:

Dog barks

4. 부모 클래스의 생성자 호출

생성자 호출 원리

  • 자식 클래스의 생성자가 호출되면 먼저 부모 클래스의 생성자가 호출된다.
  • 이는 부모 클래스의 필드와 메서드를 올바르게 초기화하기 위해 필요하다.

자동 호출

  • 부모 클래스에 기본 생성자가 있다면 자식 클래스는 명시적으로 부모 생성자를 호출하지 않아도 된다.
class Animal {
    Animal() {
        System.out.println("Animal 생성자 호출");
    }
}

class Dog extends Animal {
    Dog() {
        System.out.println("Dog 생성자 호출");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
    }
}

출력:

Animal 생성자 호출
Dog 생성자 호출

부모 생성자 명시적 호출

  • 부모 클래스에 기본 생성자가 없고 매개변수가 있는 생성자만 있다면, 자식 클래스에서 반드시 super를 사용해 명시적으로 부모 생성자를 호출해야 한다.
  • 만약 자식 클래스에서 부모 생성자를 명시적으로 호출하지 않으면, 컴파일러는 기본적으로 super()(즉, 매개변수가 없는 기본 생성자)를 자동으로 삽입합니다.
  • 부모 클래스에 기본 생성자가 없으면 super() 호출이 실패하므로, 컴파일 에러가 발생합니다.
  • 따라서 부모 클래스의 매개변수가 있는 생성자를 명시적으로 호출해야 합니다.
class Animal {
    Animal(String name) {
        System.out.println("Animal 생성자: " + name);
    }
}

class Dog extends Animal {
    Dog(String name) {
        super(name); // 부모 생성자 호출
        System.out.println("Dog 생성자: " + name);
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("Buddy");
    }
}

출력:

Animal 생성자: Buddy
Dog 생성자: Buddy

5. 메서드 오버라이드(Method Override)

오버라이드란?

오버라이드는 부모 클래스의 메서드를 자식 클래스에서 재정의하는 것을 의미한다.

이를 통해 부모 클래스의 기본 동작을 자식 클래스의 요구에 맞게 변경할 수 있다.

class Animal {
    void sound() {
        System.out.println("Animal makes a sound");
    }
}

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

public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.sound(); // "Dog barks" 출력
    }
}

6. super 키워드

  • super는 부모 클래스의 멤버(필드, 메서드, 생성자)를 참조하거나 호출할 때 사용된다.

사용 예제

  1. 부모 클래스 생성자 호출:

    class Animal {
        Animal(String name) {
            System.out.println("Animal 생성자: " + name);
        }
    }
    
    class Dog extends Animal {
        Dog(String name) {
            super(name); // 부모 생성자 호출
            System.out.println("Dog 생성자: " + name);
        }
    }
    
  2. 부모 클래스 메서드 호출:

    class Animal {
        void eat() {
            System.out.println("Animal is eating");
        }
    }
    
    class Dog extends Animal {
        @Override
        void eat() {
            super.eat(); // 부모 메서드 호출
            System.out.println("Dog is eating happily");
        }
    }
    

7. 상속의 특징과 제한

특징

  1. 단일 상속: Java는 단일 상속만 지원하며, 하나의 부모 클래스만 상속 가능.
  2. 접근 제어자:
    • public: 어디서나 접근 가능.
    • protected: 같은 패키지 및 자식 클래스에서 접근 가능.
    • private: 상속은 가능하지만 직접 접근 불가.

제한

  • 부모 클래스가 final로 선언되면 상속할 수 없다.
  • 부모 클래스의 final 메서드는 오버라이드할 수 없다.

8. 상속의 장단점

장점

  1. 코드 재사용성 증가: 부모 클래스의 기능을 자식 클래스에서 재활용.
  2. 유지보수 용이: 공통 코드를 부모 클래스에 모아 관리.
  3. 다형성 구현 가능: 부모 타입으로 다양한 자식 클래스 처리 가능.

단점

  1. 결합도 증가: 부모-자식 간 의존성이 높아질 수 있음.
  2. 복잡성 증가: 잘못된 설계 시 클래스 계층 구조가 복잡해짐.
  3. 모든 상황에 적합하지 않음: 조합(Composition)이 더 적합한 경우도 있음.

9. 상속과 조합의 비교

상속조합(Composition)
"is-a" 관계를 나타냄"has-a" 관계를 나타냄
코드 재사용성이 높음코드의 유연성이 높음
클래스 계층 구조가 복잡해질 수 있음단순한 구조 유지 가능

10. 한 줄 요약

상속은 코드 재사용과 확장을 가능하게 하며, 객체지향 프로그래밍에서 클래스 간 계층 구조 설계와 다형성 구현을 위한 강력한 도구이다.

0개의 댓글