[Java vs Python] 오버로딩/오버라이딩 한 장 정리

NANO·5일 전

알고리즘 Cheat Sheet 시리즈는 코딩 테스트를 풀다가 "이거 자바에선 뭐였지?", "파이썬은 어떻게 했더라?" 싶을 때 바로 펼쳐 보려고 만든 개인 참고용 정리입니다.
Java와 Python을 나란히 놓고, 문법 차이 때문에 실수하기 쉬운 부분만 짧게 정리합니다.

이번 주제는 오버로딩과 오버라이딩입니다.
이름이 비슷해서 헷갈리지만 전혀 다른 개념이고, 면접 단골 질문이기도 합니다.
코테에서는 직접 만든 클래스를 정렬하거나 HashMap 키로 쓸 때 오버라이딩이 꼭 필요합니다.


1. 한눈에 비교

구분오버로딩 (Overloading)오버라이딩 (Overriding)
한 줄 정의같은 이름, 다른 매개변수로 메서드를 여러 개 생성부모의 메서드를 자식이 다시 정의
관계같은 클래스 안상속 관계 (부모 ↔ 자식)
메서드 이름같다같다
매개변수달라야 한다 (개수 · 타입 · 순서)같아야 한다
반환 타입상관없다 (반환 타입만 다르면 안 됨)같거나 하위 타입
결정 시점컴파일할 때실행할 때 (실제 객체 기준)
자바⭕⭕
파이썬❌ 지원하지 않는다⭕

오버로딩은 "새로 추가(load)", 오버라이딩은 "덮어쓰기(ride over)" 로 외우자!


2. 오버로딩

자바: 매개변수가 다르면 같은 이름을 쓸 수 있다

class Calc {
    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; }          // 타입이 다름
}

Calc c = new Calc();
c.add(1, 2);        // 3      → 첫 번째
c.add(1, 2, 3);     // 6      → 두 번째
c.add(1.5, 2.5);    // 4.0    → 세 번째

우리가 늘 쓰는 Math.max(int, int), Math.max(long, long), Math.max(double, double)과 System.out.println()도 오버로딩이다.

int add(int a, int b)  { ... }
long add(int a, int b) { ... }   // ❌ 반환 타입만 다른 것은 오버로딩이 아니다 (컴파일 에러)

파이썬: 같은 이름으로 다시 정의하면 덮어쓴다

def add(a, b):
    return a + b

def add(a, b, c):          # 앞의 add를 덮어쓴다
    return a + b + c

add(1, 2)                  # ❌ TypeError: add() missing 1 required positional argument: 'c'

파이썬은 대신 기본값 인자와 가변 인자로 같은 효과를 낸다.

def add(a, b, c=0):        # 기본값 인자
    return a + b + c

add(1, 2)                  # 3
add(1, 2, 3)               # 6

def add_all(*nums):        # 가변 인자 (몇 개든 받는다)
    return sum(nums)

add_all(1, 2, 3, 4)        # 10

생성자 오버로딩

상황자바파이썬
인자 개수에 따라 다르게생성자를 여러 개 정의__init__에 기본값 인자
다른 생성자 호출this(...)-
class Point {
    int x, y;
    Point()             { this(0, 0); }        // 다른 생성자를 호출
    Point(int x, int y) { this.x = x; this.y = y; }
}
class Point:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

3. 오버라이딩

상속 문법부터

항목자바파이썬
상속class Dog extends Animalclass Dog(Animal):
부모 생성자 호출super(name);super().__init__(name)
부모 메서드 호출super.speak();super().speak()
오버라이딩 표시@Override없음 (같은 이름으로 정의하면 끝)
다중 상속❌ (인터페이스는 여러 개 가능)⭕
class Animal {
    String name;
    Animal(String name) { this.name = name; }

    void speak() { System.out.println("..."); }
}

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

    @Override
    void speak() {                       // 부모의 speak를 다시 정의
        super.speak();                   // 부모 것도 부르고 싶을 때
        System.out.println("멍멍");
    }
}

Animal a = new Dog("바둑이");
a.speak();   // "..." 다음에 "멍멍"  ← 변수 타입(Animal)이 아니라 실제 객체(Dog) 기준
class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        print("...")

class Dog(Animal):
    def __init__(self, name):
        super().__init__(name)

    def speak(self):                     # 같은 이름으로 정의하면 오버라이딩
        super().speak()
        print("멍멍")

Dog("바둑이").speak()   # "..." 다음에 "멍멍"

자바 오버라이딩 규칙

  • 메서드 이름과 매개변수가 부모와 똑같아야 한다.
  • 접근 범위를 더 좁힐 수 없다 (public → private 불가).
  • static, final, private 메서드는 오버라이딩할 수 없다.

4. 코테에서 오버라이딩하는 메서드

직접 만든 클래스를 출력, 비교, 해시, 정렬에 쓰려면 아래 메서드를 다시 정의해야 한다.

용도자바파이썬안 하면 생기는 일
출력toString()__repr__ / __str__Point@1b6d3586 같은 주소가 출력된다
값이 같은지equals(Object o)__eq__(self, other)값이 같아도 다른 객체로 본다
해시 (HashMap · HashSet)hashCode()__hash__(self)값이 같은 키를 못 찾는다
정렬 · 우선순위 큐compareTo() (Comparable)__lt__(self, other)정렬할 때 에러가 난다
class Point implements Comparable<Point> {
    int x, y;
    Point(int x, int y) { this.x = x; this.y = y; }

    @Override
    public String toString() {
        return "(" + x + ", " + y + ")";
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Point)) return false;
        Point p = (Point) o;
        return x == p.x && y == p.y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }

    @Override
    public int compareTo(Point o) {           // x 오름차순, 같으면 y 오름차순
        if (x != o.x) return Integer.compare(x, o.x);
        return Integer.compare(y, o.y);
    }
}

Set<Point> set = new HashSet<>();
set.add(new Point(1, 2));
set.contains(new Point(1, 2));   // true  (equals + hashCode 덕분)

PriorityQueue<Point> pq = new PriorityQueue<>();   // compareTo 기준으로 꺼낸다
class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __repr__(self):
        return f"({self.x}, {self.y})"

    def __eq__(self, other):
        return (self.x, self.y) == (other.x, other.y)

    def __hash__(self):
        return hash((self.x, self.y))

    def __lt__(self, other):                 # x 오름차순, 같으면 y 오름차순
        return (self.x, self.y) < (other.x, other.y)

s = {Point(1, 2)}
Point(1, 2) in s                 # True

sorted([Point(2, 1), Point(1, 5)])   # [(1, 5), (2, 1)]

더 짧게 쓰는 방법 (사실 이건 외우기 좀 힘들지도)

방법코드자동으로 만들어 주는 것
자바 record (16+)record Point(int x, int y) {}equals, hashCode, toString
파이썬 dataclass@dataclass(frozen=True, order=True)__eq__, __hash__, __lt__, __repr__
파이썬 튜플(x, y)전부 (코테에서는 이게 제일 간단)
from dataclasses import dataclass

@dataclass(frozen=True, order=True)
class Point:
    x: int
    y: int

5. 체크포인트

equals(Point p)는 오버라이딩이 아니라 오버로딩이다

public boolean equals(Point p) {      // ❌ 매개변수 타입이 Object가 아니다
    return x == p.x && y == p.y;
}

부모(Object)의 equals(Object o)와 매개변수 타입이 달라서 오버라이딩이 아니라 오버로딩이 된다.
HashSet은 equals(Object)를 부르기 때문에 이 메서드는 쓰이지 않고, 값이 같아도 못 찾는다.

@Override를 항상 붙이자! 위 코드에 @Override를 붙이면 컴파일 에러로 바로 알려 준다.

그 밖에

  • equals를 재정의하면 hashCode도 반드시 함께... equals만 하면 HashSet / HashMap에서 값이 같은 객체를 못 찾는다.

  • 파이썬에서 __eq__만 정의하면 해시가 불가능해진다. TypeError: unhashable type이 나므로 __hash__도 같이 정의한다.

  • 파이썬 리스트를 출력하면 __str__이 아니라 __repr__을 쓴다. 하나만 정의할 거면 __repr__을 정의하자.

  • 자바 static 메서드는 오버라이딩되지 않는다. 자식에 같은 이름으로 만들면 가려질(hiding) 뿐, 변수 타입 기준으로 호출된다.

  • 파이썬 기본값 인자에 리스트를 쓰지 말자. 기본값은 함수 정의 시 한 번만 만들어져서 호출끼리 공유된다.

    def add(x, lst=[]):          # ❌
        lst.append(x)
        return lst
    
    add(1)   # [1]
    add(2)   # [1, 2]  ← 이전 호출의 리스트가 남아 있다
    
    def add(x, lst=None):        # ⭕
        if lst is None:
            lst = []
        lst.append(x)
        return lst

💡 이것만 기억하자

  1. 오버로딩: 같은 이름, 다른 매개변수
    오버라이딩: 부모 메서드를 자식이 재정의
  2. 파이썬은 오버로딩이 없다. 같은 이름으로 다시 정의하면 덮어쓴다. 기본값 인자와 *args로 대신한다.
  3. 부모 호출:
    자바: super.메서드()
    파이썬: super().메서드()
  4. 직접 만든 클래스를 HashSet / HashMap에 넣으려면 equals + hashCode (파이썬은 __eq__ + __hash__)
  5. 정렬/우선순위 큐에 넣으려면 compareTo (파이썬은 __lt__)
  6. 자바는 @Override를 항상 붙이자! equals(Point p) 같은 실수를 컴파일러가 잡아 준다.
profile
즐거운 토마토

0개의 댓글