[TIL] 자바의 상속, 오버라이딩

냠냠빈·2024년 11월 21일

상속이란?

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


상속이 왜 필요한가?

  • 예를 들어 밑의 코드를 보면, 클래스 '오리', '흰오리', '청둥오리' 모두 같은 '날다' 메소드를 갖추고 있는데 호출문도 모두 중복이 된다. 지금은 3개의 클래스여서 크게 불편하지는 않는데 만약 100개의 클래스가 모두 System.out.println("오리가 날개로 날아갑니다."); 같은 출력문을 사용하게 되면? 코드가 길어진다. 이를 해결하고 더 나아가 여러 오리가 '날다' 방식이 다르고 각 클래스의 고유의 행동을 구현하는 데에 필요한 방법이 '상속'이다.
public class Main {
    public static void main(String[] args) {
        청둥오리 a청둥오리 = new 청둥오리();
        a청둥오리.날다();
        // 출력 : 오리가 날개로 날아갑니다.

        흰오리 a흰오리 = new 흰오리();
        a흰오리.날다();
        // 출력 : 오리가 날개로 날아갑니다.
    }
}

class 오리 {
    void 날다() {
        System.out.println("오리가 날개로 날아갑니다.");
    }
}

class 흰오리 {
    void 날다() {
        System.out.println("오리가 날개로 날아갑니다.");
    }
}

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

상속의 기본 개념

부모 클래스(Superclass)

  • 상속의 대상이 되는 클래스. 자식 클래스에게 필드와 메서드를 물려준다.

자식 클래스(Subclass)

  • 부모 클래스를 상속받아 확장된 기능을 추가하거나 기존 메서드를 재정의(Overriding)할 수 있다.

기본 문법

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

class 자식클래스 extends 부모클래스 {
    // 부모의 필드와 메서드 상속
    // 자식 클래스만의 새로운 필드와 메서드 추가 가능
}
  • 'extends' 키워드를 통해 부모클래스의 필드와 메서드를 사용이 가능하다.

상속의 특징

  1. 단일 상속: 자바는 단일 상속만 지원한다(하나의 부모 클래스만 상속 가능).
    다중 상속으로 인한 모호성을 방지하기 위함이다.

예시코드

class Parent {}
class Child extends Parent {} // 가능
  1. 다중 계층 상속: 여러 계층에 걸쳐 상속이 가능하다.

예시코드

class GrandParent {}
class Parent extends GrandParent {}
class Child extends Parent {}
  1. Object 클래스 상속: 자바의 모든 클래스는 암묵적으로 Object 클래스를 상속받는다. Object 클래스의 메서드(toString, equals, hashCode 등)를 재정의할 수 있다.

  2. private 멤버는 상속되지 않음: 부모 클래스의 private 접근 제어자를 가진 필드나 메서드는 자식 클래스에서 접근할 수 없다. 하지만 간접적으로 사용할 수 있는 getter, setter 메서드는 상속받아 사용 가능하다.


상속의 장점

  • 코드 재사용성: 부모 클래스의 코드를 반복하지 않고 자식 클래스에서 재사용할 수 있다.
  • 유지보수성:공통 기능을 부모 클래스에 작성하면 수정 시 모든 자식 클래스에 반영된다.
  • 다형성(Polymorphism) 구현: 부모 클래스의 참조 변수로 자식 클래스 객체를 참조할 수 있어 동적 바인딩이 가능하다.

상속 예제

  • 기본 상속
class Animal {
    void sound() {
        System.out.println("Animal makes a sound");
    }
}

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

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

super 키워드

부모 클래스의 멤버(필드, 메서드)에 접근하거나 부모 생성자를 호출할 때 사용한다.

  • 부모 필드와 메서드 호출
class Parent {
    String name = "Parent";

    void display() {
        System.out.println("Parent display");
    }
}

class Child extends Parent {
    String name = "Child";

    void display() {
        System.out.println("Child display");
    }

    void showParentInfo() {
        System.out.println(super.name); // "Parent"
        super.display();               // "Parent display"
    }
}
  • 부모 생성자 호출
class Parent {
    Parent(String message) {
        System.out.println("Parent Constructor: " + message);
    }
}

class Child extends Parent {
    Child() {
        super("Hello from Parent!"); // 부모 클래스 생성자 호출
    }
}

메서드 오버라이딩

부모 클래스의 메서드를 자식 클래스에서 재정의(Overriding)한다.

@Override 애너테이션을 사용하여 컴파일러에게 오버라이딩임을 알린다.
class Parent {
    void greet() {
        System.out.println("Hello from Parent");
    }
}

class Child extends Parent {
    @Override
    void greet() {
        System.out.println("Hello from Child");
    }
}

public class Main {
    public static void main(String[] args) {
        Parent obj = new Child();
        obj.greet(); // "Hello from Child"
    }
}

상속 사용 시 주의사항

  • is-a 관계 확인: 상속은 "is-a" 관계를 만족해야 한다.
    예: Dog is an Animal.

  • 부모 클래스 변경의 영향: 부모 클래스 수정은 모든 자식 클래스에 영향을 줄 수 있으므로 신중히 해야 한다.

  • 다중 상속의 대안: 다중 상속이 필요하다면 인터페이스를 활용할 수 있다.

  • 상속 대신 조합 사용 고려: 상속은 강한 결합을 만드므로 필요 이상으로 의존성을 높일 수 있다. "상속보다는 조합(Composition)을 사용하라"는 원칙도 고려해야 한다.


정리 : 상속 vs 인터페이스

특징상속인터페이스
관계is-a 관계can-do 관계
다중 구현 여부단일 상속만 가능다중 구현 가능
접근 제한자부모 클래스의 접근 제어자 제한 적용기본적으로 모든 메서드는 public
구현 여부부모 클래스의 구현 상속구현 강제 (추상 메서드)
profile
다 먹어버릴거야!

0개의 댓글