2026-03-29
Overriding(오버라이딩)
상속 관계에서 부모 클래스가 가진 메서드를 자식 클래스가 자신의 상황에 맞게 다시 구현하는 것
⇒ 부모가 만든 기능의 틀은 유지하되, 자식이 그 동작 내용을 바꿔서 사용하는 개념
예시
class Animal {
void sound() {
System.out.println("동물이 소리를 냅니다.");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("멍멍");
}
}
⇒ Dog는 Animal의 sound() 메서드를 오버라이딩
오버라이딩 특징
다음 조건을 만족해야 함
- 메서드 이름이 같아야 한다 부모와 자식의 메서드 이름이 같아야 한다.
- 매개변수가 같아야 한다 이름만 같고 파라미터가 다르면 오버라이딩이 아니라 오버로딩이다.
- 반환 타입이 같아야 한다 정확히는 같거나, 더 구체적인 하위 타입까지는 허용되는 경우가 있다.
- 상속 관계여야 한다 부모-자식 관계가 아니면 오버라이딩이 아니다.
-
접근 범위는 더 좁아질 수 없다 부모가
public인데 자식이private로 바꾸면 안 된다.class Parent { public void hello() {} } class Child extends Parent { @Override private void hello() {} // 오류 }이건 불가능
왜 중요한가?
오버라이딩은 다형성과 연결
Animal animal = new Dog();
animal.sound();
⇒ 겉으로는 Animal 타입이지만, 실제 객체는 Dog이기 때문에 Dog의 sound()가 실행
⇒ 실행 시점에 어떤 메서드가 호출될지 결정된다.
→ 런타임 바인딩 = 동적 바인딩
언제 쓰나?
- 부모의 기본 동작을 자식마다 다르게 구현하고 싶을 때
- 공통 인터페이스는 유지하면서 실제 동작은 다르게 하고 싶을 때
- 다형성을 활용한 유연한 설계를 하고 싶을 때
예시
Payment의pay()Animal의sound()Shape의draw()
⇒ 이런 구조에서 자식 클래스마다 다른 동작을 구현할 수 있다.
@Override를 쓰는 이유
필수는 아니지만 거의 항상 쓰는 것이 좋음
@Override
void sound() {
System.out.println("멍멍");
}
이걸 쓰면 컴파일러가 “정말 부모 메서드를 재정의한 게 맞는지” 확인해준다.
예를 들어 오타가 나면 바로 잡아준다.
@Override
void soudn() { // 오타
System.out.println("멍멍");
}
이 경우 @Override가 없으면 그냥 새로운 메서드가 만들어질 수 있는데,
@Override가 있으면 컴파일 에러로 알려준다.
⇒ 실수를 줄이기 위해 사용하는 것
Overloading(오버로딩)
같은 이름의 메서드를 여러 개 정의하되, 매개변수를 다르게 하는 것
⇒ 이름은 같지만 전달받는 값의 타입이나 개수가 다르면, 자바는 이를 다른 메서드로 구분
예시
class Calculator {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
}
⇒ 모두 add라는 같은 이름을 쓰지만, 파라미터가 다르기 때문에 가능
특징
- 메서드 이름은 같아야 한다 오버로딩은 “같은 기능군”을 묶기 위한 개념이라 이름이 같아야 한다.
- 매개변수가 달라야 한다
다음 중 하나라도 달라야 한다.
- 개수
- 타입
- 순서
예:
void print(int a) {} void print(String a) {} void print(int a, int b) {} void print(String a, int b) {}
반환형만 다르면 안 된다
int sum(int a, int b) { return a + b; }
double sum(int a, int b) { return a + b; } // 불가능
이건 오버로딩이 아님
- 호출할 때 자바는 매개변수 기준으로 메서드를 구분하기 때문
- 반환형만 다르게 하는 것은 허용되지 않음
언제 결정되나?
오버로딩은 컴파일 시점에 어떤 메서드를 호출할지 결정
예시
Calculator c = new Calculator();
c.add(1, 2);
c.add(1.5, 2.5);
⇒ 컴파일러가 전달된 인자 타입을 보고 어떤 add()를 호출할지 미리 정한다.
⇒ 오버로딩은 정적 바인딩과 관련이 있다.
언제 쓰나?
- 같은 의미의 기능을 다양한 입력값으로 처리하고 싶을 때
- 메서드 이름을 일관되게 유지하면서 사용 편의성을 높이고 싶을 때
예시
println()add()parse()
⇒ 같은 메서드가 다양한 타입을 받아 처리하는 경우가 대표적
Override와 Overload 차이
- 오버라이딩은 상속 관계에서 동작을 재정의
- 오버로딩은 같은 이름의 메서드를 여러 방식으로 제공
| 구분 | Overriding | Overloading |
|---|---|---|
| 의미 | 부모 메서드 재정의 | 같은 이름의 메서드 여러 개 정의 |
| 상속 관계 | 필요함 | 필요 없음 |
| 메서드 이름 | 같음 | 같음 |
| 매개변수 | 같아야 함 | 달라야 함 |
| 반환형 | 같아야 함 | 반환형만 달라서는 안 됨 |
| 결정 시점 | 런타임 | 컴파일 시점 |
| 관련 개념 | 다형성, 동적 바인딩 | 편의성, 정적 바인딩 |
요약
- 오버라이딩 = 상속 + 재정의 + 런타임
- 상속 관계에서 부모 클래스의 메서드를 자식 클래스가 재정의하는 것
- 런타임에 결정
- 오버로딩 = 같은 이름 + 파라미터 다름 + 컴파일
- 같은 이름의 메서드를 매개변수를 다르게 해서 여러 개 정의하는 것
- 컴파일 시점에 결정