코드 한 줄의 기록

Java 상속과 오버라이딩 완벽 가이드: super 활용법까지 쉽게 이해하기 본문

JAVA

Java 상속과 오버라이딩 완벽 가이드: super 활용법까지 쉽게 이해하기

CodeByJin 2025. 10. 9. 14:58
반응형

Java의 상속(Inheritance)오버라이딩(Overriding)은 객체지향 프로그래밍의 핵심 개념으로, 코드 재사용성과 확장성을 극대화합니다. 이 글에서는 Java 상속의 기초부터 super 키워드를 활용한 세부 규칙까지 차근차근 살펴보며, 실습 예제와 함께 이해를 돕겠습니다.

상속(Inheritance)이란 무엇인가?

상속은 “이미 존재하는 클래스(부모 클래스)의 속성과 기능을 재사용하고, 추가·확장하는 구조”를 의미합니다. Java에서는 extends 키워드를 사용해 상속 관계를 정의하고, 코드 중복을 줄일 수 있습니다.

// 부모 클래스
public class Animal {
    protected String name;
    
    public Animal(String name) {
        this.name = name;
    }
    
    public void speak() {
        System.out.println(name + "가(이) 소리를 냅니다.");
    }
}

// 자식 클래스
public class Dog extends Animal {
    public Dog(String name) {
        super(name);  // 부모 생성자 호출
    }
}

 

위 예제에서 Dog 클래스는 Animal 클래스를 상속받아 name 필드와 speak() 메서드를 그대로 사용할 수 있습니다.

상속의 장점과 주의사항

장점

  • 코드 재사용: 한번 작성한 코드(필드·메서드)를 여러 자식 클래스에서 공유
  • 기능 확장: 부모 클래스 기반으로 새로운 기능 추가 가능
  • 유지보수 효율성: 공통 로직을 부모 클래스에 모아 두면 수정 시 한 곳만 변경

주의사항

  • 다중 상속 불가: Java는 클래스 다중 상속을 허용하지 않음. 인터페이스로 보완
  • 상속 관계 설계: 무분별한 상속은 결합도를 높여 오히려 유지보수 어려움
  • protected 접근 제한자: 상속할 때 필드·메서드 접근 제어 필요

오버라이딩(Overriding)이란?

오버라이딩은 부모 클래스의 메서드를 자식 클래스에서 재정의하는 것을 말합니다. 메서드 시그니처(이름·매개변수·리턴 타입)는 그대로 유지하면서 내부 구현만 바꿉니다. 주로 다형성(Polymorphism) 구현에 사용됩니다.

public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    @Override
    public void speak() {
        System.out.println(name + "가(이) 멍멍 짖습니다.");
    }
}
  • @Override 어노테이션: 부모 메서드를 제대로 오버라이딩했는지 컴파일러가 검증
  • 시그니처 불일치 시 컴파일 오류 발생

super 키워드 활용법

super부모 클래스의 멤버(필드·메서드·생성자)를 가리키는 참조 변수입니다. 세 가지 주요 활용 규칙을 알아봅시다.

 

부모 생성자 호출: super(...)

  • 자식 클래스 생성자 첫 줄에서만 호출 가능
  • 부모 클래스에 매개변수가 있는 생성자가 있을 때 반드시 명시해야 함
public class Cat extends Animal {
    private String color;
    
    public Cat(String name, String color) {
        super(name);       // 부모 생성자 호출
        this.color = color;
    }
}

 

부모 메서드 호출: super.methodName()

  • 오버라이딩한 메서드 안에서 부모 메서드 기능을 함께 사용하고 싶을 때
  • super 없이 this.methodName()를 호출하면 재귀 호출이 되므로 주의
@Override
public void speak() {
    super.speak();  // 부모의 기본 동작 출력
    System.out.println(name + "가(이) 부드럽게 야옹합니다.");
}

 

부모 필드 접근: super.fieldName

  • 자식 클래스에 같은 이름의 필드가 있을 때 구분 용도
  • 일반적으로 잘 쓰이지 않지만, 네임 충돌 해결에 사용
public class Bird extends Animal {
    protected String name;  // 부모와 필드명이 동일
    
    public Bird(String name) {
        super(name);
        this.name = "[새] " + name;
    }
    
    public void printNames() {
        System.out.println("부모 이름: " + super.name);
        System.out.println("자식 이름: " + this.name);
    }
}

오버라이딩 규칙과 주의사항

  1. 접근 제어자 확대 가능
    - 부모보다 넓은 접근 범위를 허용
    - 예: 부모가 protected일 때, 자식에서 public으로 선언 가능
  2. 예외(Exception) 제한
    - 부모 메서드가 던지지 않은 예외를 새롭게 던질 수 없음
    - 부모가 IOException 던질 때, 자식은 IOException 혹은 그 자식 예외만 선언 가능
  3. static 메서드는 오버라이딩 불가
    - 클래스 메서드(static)는 재정의가 아닌 숨김(hiding)
    - 호출 시 참조 타입에 따라 동작이 결정됨
  4. final 메서드는 오버라이딩 불가
    - 보안·안정성이 필요한 메서드는 final로 선언해 변경 방지

다형성과 상속 활용 예제

상속과 오버라이딩을 활용해 동물원 프로그램을 만들어 봅시다.

public class Zoo {
    public static void main(String[] args) {
        Animal[] animals = {
            new Dog("바둑이"),
            new Cat("나비"),
            new Bird("짹짹이")
        };
        
        for (Animal a : animals) {
            a.speak();  // 각 동물별 오버라이딩된 메서드 호출
        }
    }
}

 

실행 결과
바둑이가 멍멍 짖습니다.
나비가 부드럽게 야옹합니다.
[새] 짹짹이가 소리를 냅니다.

이처럼 상속과 오버라이딩을 통해 코드 중복 없이도 다양한 동작을 구현할 수 있습니다.

상속 설계 시 고려할 점

  1. IS-A 관계: 상속은 “~은 ~이다” 관계에만 사용
    - 예: Dog is an Animal → 상속 가능
    - 예: Car is an Animal → 상속 부적절
  2. 인터페이스 활용: 다중 상속 대신 인터페이스를 통해 다형성 확보
  3. 컴포지션 우선: “HAS-A” 관계일 땐 합성(composition) 사용 권장
    - 예: Engine 을 필드로 가진 Car

정리 및 실습 과제

이번 글에서는 Java 상속의 기본 개념과 오버라이딩, super 키워드 활용법, 설계 시 주의사항까지 살펴보았습니다.

 

실습 과제

  • 새로운 동물 클래스를 추가해 상속 구조 확장하기
  • 부모 생성자를 여러 개 정의하고, 자식에서 super 로 적절히 호출해 보기
  • 오버라이딩 규칙 위반 시 컴파일 오류 메시지 확인하며 이해하기

이 과제를 통해 Java 객체지향 설계의 핵심 원칙을 더욱 단단히 다져 보세요!

위 예제와 설명을 따라 작성하며 이해했다면, 여러분도 Java 상속과 오버라이딩의 강력함을 경험할 수 있을 것입니다. 본 내용을 블로그에 게재하며 다른 개발자와 지식을 공유해 보세요!

 

 

Java 객체 생성 완벽 가이드: 생성자, 정적 팩토리 메서드, 생성자 체이닝 총정리

이 글에서는 Java에서 객체를 생성하는 주요 기법인 생성자(Constructor), 정적 팩토리 메서드(Static Factory Method), 그리고 생성자 체이닝(Constructor Chaining)을 예제 중심으로 쉽고 자연스럽게 소개합니다

byteandbit.tistory.com

 

반응형