메뉴 닫기

JAVA 메서드 오버라이딩 완벽 가이드, Override 키워드로 자식 클래스 재정의하기


JAVA 메서드 오버라이딩 완벽 가이드, Override 키워드로 자식 클래스 재정의하기

📌 부모 메서드를 자식 클래스에서 바꿔 쓰는 방법, 오버라이딩 개념과 예제를 쉽게 알려드립니다

안녕하세요.
오늘은 자바(Java)를 공부하면서 반드시 이해하고 넘어가야 할 중요한 개념 중 하나인 메서드 오버라이딩(Overriding)에 대해 알아보려고 해요.
상속을 통해 부모 클래스의 메서드를 자식 클래스가 사용할 수 있게 되는 건 아시죠?
하지만 그 기능을 그대로 쓰지 않고, 자식 클래스만의 방식으로 바꾸고 싶을 때 사용할 수 있는 것이 바로 오버라이딩입니다.
처음에는 비슷한 이름의 오버로딩과 헷갈리기 쉽지만, 기능과 목적은 완전히 다르니 이번 기회에 확실히 정리해보세요.

이 글에서는 오버라이딩의 개념부터 자바에서 사용하는 @Override 어노테이션의 역할, 실전 코드 예제, 오버로딩과의 차이점, 그리고 오버라이딩 시 주의할 점까지 친절하게 설명드릴게요.
자바를 처음 배우는 분들뿐만 아니라 객체지향 프로그래밍을 좀 더 깊이 이해하고 싶은 분들에게도 큰 도움이 될 거예요.







🔗 메서드 오버라이딩이란?

메서드 오버라이딩(Method Overriding)은 자바에서 상속받은 메서드를 자식 클래스에서 재정의하는 기능입니다.
부모 클래스에 정의된 메서드가 마음에 들지 않거나, 자식 클래스에 더 적합한 동작으로 바꾸고 싶을 때 사용하죠.
즉, 동일한 메서드 이름과 매개변수, 반환형을 가진 상태에서 내용(기능)만 바꿔서 구현하는 것입니다.

이 기능은 특히 객체지향 프로그래밍에서 다형성(Polymorphism)을 구현할 때 매우 중요한 역할을 합니다.
같은 메서드 이름을 호출하더라도 실제 어떤 동작이 실행될지는 객체의 타입에 따라 달라지기 때문이에요.

CODE BLOCK
class Animal {
    void sound() {
        System.out.println("동물이 소리를 낸다");
    }
}

class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("강아지가 멍멍 짖는다");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.sound(); // 강아지가 멍멍 짖는다
    }
}

위 예제에서 animal은 Animal 타입이지만 실제 객체는 Dog입니다.
따라서 sound() 메서드를 호출하면 Animal의 것이 아닌, Dog에서 오버라이딩한 메서드가 실행되는 것이죠.
이처럼 오버라이딩은 유연하고 확장성 있는 프로그램을 설계할 수 있게 도와주는 핵심 도구입니다.

💡 TIP: 오버라이딩은 자식 클래스의 객체를 부모 타입으로 다루더라도, 재정의된 메서드가 호출되므로 다양한 객체 간 호환성과 유연성을 확보할 수 있어요.


🛠️ Override 어노테이션의 역할

자바에서 오버라이딩을 할 때 꼭 함께 사용하는 것이 바로 @Override 어노테이션입니다.
이 어노테이션은 “이 메서드는 부모 클래스의 메서드를 재정의한 것”임을 컴파일러에게 명확히 알려주는 역할을 해요.

@Override를 사용하지 않아도 오버라이딩은 가능하지만, 실수로 메서드 이름을 틀리거나 매개변수 타입이 다르면 정상적인 오버라이딩이 되지 않고 단순히 새로운 메서드가 정의되는 문제가 발생할 수 있어요.
이때 @Override를 붙여두면 컴파일 시 오류를 바로 알려주기 때문에 버그를 사전에 방지할 수 있습니다.

CODE BLOCK
class Animal {
    void move() {
        System.out.println("움직인다");
    }
}

class Bird extends Animal {
    @Override
    void move() {
        System.out.println("날아서 이동한다");
    }
}

위 예제처럼 @Override를 붙이면 컴파일러는 Bird 클래스의 move()가 Animal 클래스의 메서드를 정확히 오버라이딩했는지 확인해줍니다.
만약 move가 아니라 ‘moove’처럼 오타가 났다면 컴파일 에러로 즉시 알려줘요.

💎 핵심 포인트:
@Override는 선택 사항이지만, 개발 시 반드시 사용하는 것이 권장됩니다.
컴파일러가 오버라이딩 여부를 검증해주기 때문에 실수 방지와 가독성 향상에 큰 도움이 됩니다.







⚙️ 오버라이딩 조건과 규칙

자바에서 메서드 오버라이딩이 제대로 작동하기 위해서는 몇 가지 필수 조건과 규칙이 있습니다.
이 규칙을 지키지 않으면 오버라이딩이 되지 않거나, 컴파일 오류가 발생할 수 있어요.
자주 실수하기 쉬운 부분이니 꼭 기억해두세요.

  • 🧩메서드 이름, 매개변수, 반환형이 부모 클래스와 동일해야 함
  • 🔐접근 제어자는 동일하거나 더 넓은 범위여야 함 (예: protected → public)
  • 🚫private, static, final 메서드는 오버라이딩 불가
  • 📄예외(Exception)는 부모보다 더 많은 체크 예외를 선언하면 안 됨

예를 들어, 부모 클래스에서 protected로 선언된 메서드를 자식 클래스에서 private으로 바꾸는 것은 접근 제한이 좁아지기 때문에 컴파일 오류가 발생합니다.

CODE BLOCK
class Animal {
    protected void eat() {
        System.out.println("먹는다");
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("고양이가 밥을 먹는다");
    }
}

위 코드처럼 자식 클래스에서 접근 제한을 public으로 넓히는 것은 가능하지만, 좁히는 건 허용되지 않아요.

⚠️ 주의: final로 선언된 메서드는 더 이상 변경될 수 없기 때문에 자식 클래스에서 오버라이딩하려고 하면 컴파일 에러가 발생합니다.


🔍 오버라이딩과 오버로딩 차이점

오버라이딩(Overriding)과 오버로딩(Overloading)은 자바에서 매우 유사한 용어로 보이지만, 완전히 다른 개념입니다.
이 둘을 혼동하기 쉬운데요, 각각의 목적과 동작 방식을 명확히 이해하면 헷갈릴 일이 없습니다.

🔁 오버라이딩 (Overriding)

상속 관계에서 부모 클래스의 메서드를 자식 클래스가 동일한 이름, 매개변수, 반환형으로 다시 정의하는 것을 말합니다.
기존 기능을 덮어쓰는 형태이며, 주로 다형성(Polymorphism)을 구현할 때 사용됩니다.

➕ 오버로딩 (Overloading)

같은 클래스 내에서 메서드 이름은 동일하지만 매개변수의 개수나 타입이 다른 여러 메서드를 정의하는 것입니다.
동일한 동작을 다양한 입력값으로 처리할 수 있도록 하기 위한 기법이죠.

💎 핵심 포인트:
오버라이딩은 “부모 메서드를 재정의”하는 것이고, 오버로딩은 “같은 이름의 메서드를 다양하게 정의”하는 것입니다.

구분 오버라이딩 오버로딩
상속 필요 여부 필수 불필요
메서드 시그니처 동일해야 함 다양하게 정의 가능
목적 기능 재정의 다양한 입력 처리

이처럼 오버라이딩과 오버로딩은 각각의 쓰임새가 뚜렷합니다.
상속 구조 안에서는 오버라이딩을, 같은 클래스 내에서 유연한 동작을 설계할 때는 오버로딩을 사용하세요.







💡 오버라이딩 시 주의사항

오버라이딩은 자바에서 유용한 기능이지만, 몇 가지 중요한 주의사항을 지키지 않으면 예상치 못한 결과나 컴파일 오류가 발생할 수 있어요.
자주 발생하는 실수를 미리 알고 예방하는 것이 좋은 코딩 습관입니다.

  • ⚠️@Override 어노테이션을 빠뜨리면 오버라이딩 실수를 놓치기 쉬워요
  • 🔒접근 제어자가 더 좁아지면 컴파일 오류가 발생할 수 있어요
  • 🔁return 타입은 부모 메서드와 동일하거나 자식 타입만 가능해요
  • 🚫final, static, private 메서드는 오버라이딩 대상이 아닙니다

특히 static 메서드는 클래스에 귀속되는 메서드이기 때문에 인스턴스를 기반으로 한 오버라이딩이 불가능합니다.
만약 동일한 이름의 static 메서드를 정의한다면, 그것은 ‘메서드 숨김(Method Hiding)’이라는 전혀 다른 개념이에요.

⚠️ 주의: 부모 클래스에 체크 예외(checked exception)를 선언하지 않았는데, 자식 클래스에서 오버라이딩 시 더 넓은 범위의 예외를 선언하면 컴파일 에러가 발생할 수 있어요.

안정적인 오버라이딩을 위해서는 문법적 요건뿐 아니라, 코드의 의미적 일관성도 고려하는 것이 좋습니다.
즉, 부모 클래스에서 기대하는 동작과 크게 벗어나지 않는 방향으로 재정의하는 것이 바람직해요.


❓ 자주 묻는 질문 (FAQ)

오버라이딩과 오버로딩의 가장 큰 차이는 무엇인가요?
오버라이딩은 상속받은 메서드를 자식 클래스에서 재정의하는 것이고, 오버로딩은 같은 클래스 내에서 매개변수가 다른 메서드를 여러 개 정의하는 것입니다.
@Override 어노테이션은 꼭 써야 하나요?
필수는 아니지만 사용하는 것이 강력히 권장됩니다. 실수로 오버라이딩이 안 된 경우 컴파일러가 즉시 알려주기 때문입니다.
private 메서드도 오버라이딩이 가능한가요?
아니요. private 메서드는 상속되지 않기 때문에 자식 클래스에서 오버라이딩할 수 없습니다.
static 메서드도 오버라이딩할 수 있나요?
static 메서드는 클래스에 귀속되므로 오버라이딩이 불가능하며, 동일한 이름으로 정의할 경우 메서드 숨김(Method Hiding)이 발생합니다.
부모 메서드보다 더 좁은 접근 제어자로 오버라이딩할 수 있나요?
불가능합니다. 오버라이딩 시 접근 제어자는 동일하거나 더 넓어야 하며, 좁아지면 컴파일 오류가 발생합니다.
반환형이 달라도 오버라이딩이 되나요?
반환형은 동일해야 하지만, 자바 5부터는 covariant return type이 허용되어 자식 타입으로 반환하는 것은 가능합니다.
오버라이딩한 메서드에서 super 키워드는 언제 쓰나요?
자식 클래스에서 부모 클래스의 원래 메서드를 호출하고 싶을 때 super.메서드명() 형태로 사용할 수 있습니다.
예외 처리도 오버라이딩 시 영향을 받나요?
네, 부모 메서드가 던지는 예외보다 더 넓은 범위의 예외를 자식 메서드에서 선언하면 컴파일 오류가 발생합니다.



🧠 오버라이딩을 통해 자바 상속 활용도를 높여보세요

이번 글에서는 자바의 핵심 문법 중 하나인 메서드 오버라이딩(Override)에 대해 알아보았습니다.
오버라이딩은 상속받은 기능을 상황에 맞게 수정하거나 확장할 수 있도록 도와주는 매우 강력한 도구예요.

@Override 어노테이션의 사용 이유부터, 오버라이딩이 제대로 작동하기 위한 조건, 오버로딩과의 차이, 그리고 자주 하는 실수까지 하나하나 짚어봤는데요.
이제는 오버라이딩이 단순한 문법이 아닌 객체지향의 유연성과 확장성을 높이는 기법이라는 점이 명확히 다가오셨을 거라 생각합니다.

자바 코드를 좀 더 효율적으로 작성하고 싶다면 오버라이딩을 적재적소에 활용해보세요.
기능을 재정의하면서도 일관성과 안정성을 유지할 수 있는 유용한 전략이 될 수 있습니다.


🏷️ 관련 태그 : 자바오버라이딩, override, 자바상속, 자바문법, 객체지향, 자바기초, 자바예제, 오버라이딩오버로딩, java초보, @override