메서드 오버라이딩에서 접근 제어자의 범위

CJI0524·2024년 7월 8일

Java/Class

목록 보기
2/8

1. 오버라이딩시 메서드의 접근 제어자 변경 제한

부모클래스로부터 상속받은 메서드의 오버라이딩 (overriding) 시 접근 제어자는 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다. 라는 제한이 있다. 예를 들면 부모 클래스에 정의된 메서드의 접근 제어자가 protected라면, 이를 오버라이딩 하는 자식 클래스의 메서드는 접근 제어자가 protected 혹은 public 이어야 한다는 것이다. 이러한 제한을 간략히 표현한 그림은 다음과 같다.

2. 왜 이러한 제한이 있을까?

2.1. 리스코프 치환 원칙 (Liskov Substitution Principle, LSP)

리스코프 치환 원칙(Liskov Substitution Principle, LSP)은 객체 지향 프로그래밍에서 중요한 원칙 중 하나로, 바바라 리스코프(Barbara Liskov)가 1987년에 제안한 원칙이다. LSP는 "자식 클래스는 언제나 자신의 부모 클래스를 대체할 수 있어야 한다"는 개념을 포함한다. 이는 자식 클래스가 부모 클래스의 기능을 확장하거나 구체화하더라도 부모 클래스의 계약을 준수해야 한다는 의미이다. 쉽게 표현하면 프로그램에서 부모 클래스를 자식 클래스로 변경해도 정상적으로 동작해야 한다는 것이다.

이 원칙은 객체 지향 설계에서 상속을 사용하는 경우 특히 중요하며, 올바르게 적용되었을 때 코드의 재사용성과 유지보수성을 높일 수 있다. 리스코프 치환 원칙에 대해서는 추후 객체 지향 프로그래밍(Object-Oriented Programming, OOP)과 관련된 게시글에서 좀 더 자세히 다루기로 한다.

2.2. 리스코프 치환 원칙과 오버라이딩에 따른 접근 제어자 변경 제한의 관계

리스코프 치환 원칙(LSP)에 따르면, 자식 클래스는 부모 클래스를 대체할 수 있어야 한다. 하지만 부모클래스로부터 상속받은 메서드의 오버라이딩 시 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 경우 이러한 원칙을 위반하게 된다.

다음의 예시를 보자.

✍️ 작성

public class Parent {
    public void display() {
        System.out.println("Display in Parent");
    }
}


public class Child extends Parent {
    @Override
    private void display() { // 오버라이딩, 접근제어자를 public -> private 로 더 좁게 변경 
        System.out.println("Display in Child");
    }
}

public class Main {
    public static void main(String[] args) {
        Parent parent = new Parent();
        parent.display();  // Output: "Display in Parent"
        
        Parent childAsParent = new Child();
        childAsParent.display();  // Should call Child's display method
    }
}

위 코드에서 childAsParent는 Parent 타입이지만 실제로는 Child 클래스의 인스턴스이다. 부모 클래스의 display 메서드는 public이기 때문에 childAsParent.display()를 호출할 수 있어야 한다. 그러나 자식 클래스에서 display 메서드를 private로 오버라이딩했기 때문에, 외부(Main)에서 childAsParent.display()를 호출할 수 없게 된다. 이는 곧 Parent 인스턴스에서 display()를 호출하는 코드에서 Child 인스턴스가 호출하는 걸로 대체하면 에러가 발생한다는 의미이다. 즉 자식 클래스 (Child)가 부모 클래스 (Parent)를 대체하지 못하는 상황이 된 것이다.

물론 오버라이딩 시 제어자를 private이 아닌 그보단 접근 범위가 넓은 (default)protected로 변경한다면 Main 메서드에서 접근이 가능할 것이다. 다만 Main 메서드에서 접근은 가능하겠지만 결국 부모 클래스의 접근 범위보다 좁은 이상 다른 코드에선 문제를 일으킬 수 있다.

따라서 결과적으로 다음과 같은 에러가 나온다.

🖥️ 결과

error: display() has protected access in Child
        childAsParent.display();

정리하면 메서드를 오버라이딩(overriding)할 때 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경하면, 자식 클래스는 부모 클래스를 대체할 수 없게 된다. 이는 리스코프 치환 원칙을 위반하므로 금지된 것이다.

3. 해당 게시글 작성에 참고한 글 목록

자바의 정석 3판 (저자 : 남궁성)
Scientech Easy : Method Overriding in Java
[OOP] 객체지향 5대 원칙(SOLID) - 리스코프 치환 원칙 (LSP)

(※ 추후 계약에 의한 설계 (Contract By Design) 개념도 추가하여 서술한다.)

profile
개발돌이

0개의 댓글