- 오버로딩: 같은 이름의 메서드를 매개변수 시그니처만 다르게 하여 여러 개 정의 → 컴파일 타임(정적) 다형성.
- 오버라이딩: 상위 클래스/인터페이스의 메서드를 동일한 시그니처로 재정의 → 런타임(동적) 다형성.
static·final메서드는 오버라이딩이 불가(숨김‧은닉만 가능) → 설계 의도를 명확히 해야 한다.
| 개념 | 정의 | 발생 시점 | 핵심 키워드 |
|---|---|---|---|
| 오버로딩 | 메서드 이름은 같고 매개변수 개수·타입·순서가 다른 메서드를 다중 정의 | 컴파일 타임 | 정적 다형성, 메서드 시그니처 |
| 오버라이딩 | 상위 타입의 메서드를 동일 시그니처로 재정의 | 런타임 | 동적 다형성, 가상 메서드 테이블 |
📝 Tip: 오버로딩은 메서드 선택이 컴파일러 단계에서 결정되고, 오버라이딩은 실행 중 객체의 실제 타입에 따라 결정됩니다.
printInt(), printDouble() 대신 print() 하나로 통일class Calculator {
int add(int a, int b) {
return a + b;
}
// 매개변수 개수 다름
int add(int a, int b, int c) {
return a + b + c;
}
// 매개변수 타입 다름
double add(double a, double b) {
return a + b;
}
}
⚠️ 주의: 반환형만 다른 메서드는 오버로딩이 되지 않는다. 컴파일러는 반환형으로만 메서드를 구분하지 않는다.
class Animal {
void speak() {
System.out.println("...");
}
}
class Dog extends Animal {
@Override
void speak() {
System.out.println("멍멍!");
}
}
// 실행
Animal a = new Dog();
a.speak(); // 멍멍! — 런타임에 Dog.speak() 선택
static & final 메서드는 왜 오버라이딩이 안 될까?| 키워드 | 오버라이딩 여부 | 이유 |
|---|---|---|
| static | ❌ (메서드 숨김 only) | 클래스 단위로 바인딩 → 인스턴스에 귀속되지 않음 |
| final | ❌ | 상속은 가능하지만 변경 금지 의도 → JIT 인라이닝 최적화 가능 |
class Parent {
static void hello() { System.out.println("Parent"); }
}
class Child extends Parent {
static void hello() { System.out.println("Child"); } // 숨김
}
Parent p = new Child();
p.hello(); // Parent — 참조 타입 기준
🔍 메서드 숨김(Hiding): 오버라이딩과 달리 참조 변수의 타입에 따라 메서드가 결정된다.
class Base {
final void cannotChange() {}
}
class Sub extends Base {
// 컴파일 오류: cannot override final method
// void cannotChange() {}
}
static으로 올릴 때는 은닉(hiding)으로 오해하지 않도록 메서드명을 차별화하거나, Utility 클래스로 분리하라.static과 final 키워드는 오버라이딩을 제한하여 의도를 명확히 하고 성능을 최적화한다.