[Java 다형성] 오버라이딩과 오버로딩으로 보는 다형성

다형성은 하나의 객체가 여러 가지 형태로 동작할 수 있는 객체지향 프로그래밍의 핵심 특징입니다. 대표적으로 오버라이딩과 오버로딩을 예로 들 수 있다.



오버라이딩 (Overriding) + 규칙

특징

오버라이딩은 상속 관계에서 부모 클래스의 메소드를 자식 클래스에서 재정의하는 것을 의미합니다.

  • 상속 관계에서 발생
    • 부모 클래스의 메소드를 자식 클래스에서 재정의
class Parent {
    void display() {
        System.out.println("Parent");
    }
}

class Child extends Parent {
    @Override
    void display() {  // 메소드 재정의
        System.out.println("Child");
    }
}


💡 주의사항

  • static 메소드는 오버라이딩 불가
  • private 메소드는 상속되지 않으므로 오버라이딩 불가



규칙 3가지

1. 메소드 시그니처와 반환타입이 동일해야 함

  • 메소드 시그니처(method signature) : 메서드 이름, 매개변수 리스트
  • 반환 타입 : 동일하거나 하위 클래스 타입
class Parent {
    Number getValue() { return 0; }
}

class Child extends Parent {
    @Override
    Integer getValue() { return 1; }  // Integer는 Number의 하위 클래스이므로 가능
}


2. access modifier(접근 제한자)는 부모의 제한보다 자식이 더 제한할 수 없다.

  • 접근 제어자 범위: public > protected > default > private
class Parent {
    protected void display() { }
}

class Child extends Parent {
    @Override
    public void display() { }     // OK: 더 넓은 범위
    // private void display() { } // Error: 더 좁은 범위
}


3. 예외처리는 부모의 범위보다 자식이 더 큰 범위의 예외를 던질 수 없다.

  • 예외 계층: Exception > IOException > FileNotFoundException
class Parent {
    void method() throws IOException { }
}

class Child extends Parent {
    @Override
    void method() throws FileNotFoundException { } // OK: 더 구체적인 예외
    // void method() throws Exception { }         // Error: 더 큰 범위의 예외
}



오버로딩 (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;
    }
}


💡 대표적인 예시

System.out.println() 메서드는 다양한 타입(int, String, boolean 등)을 매개변수로 받을 수 있도록 오버로딩



규칙 3가지

1. 메서드 이름이 동일해야 함

2. 매개변수의 개수나 타입이 달라야 함

3. 반환 타입은 오버로딩 판단에 영향을 주지 않음

class Calculator {
    int add(int a, int b) {
        return a + b;
    }
    
    long add(long a, long b) {
        return a + b;
    }
    
    double add(double a, double b) {
        return a + b;
    }
    
    int add(int[] numbers) {
        int sum = 0;
        for(int n : numbers) {
            sum += n;
        }
        return sum;
    }
}


두 개념 모두 다형성을 구현하는 방법이지만, 오버라이딩은 상속을 통한 재정의에, 오버로딩은 메소드 확장에 초점을 맞춥니다.

댓글남기기