Search

Item 52. 다중정의는 신중히 사용하라

생성일
2023/08/01 10:06
챕터
8장 - 메서드

요약

다중 정의의 문제점

public Class CollectionClassifier { public static Stringclassify(Set<?> s) { return "집합"; } public static String Classify(List<?> lst) { return "리스트"; } public static String Classify(Collection<?> c) { return "그외"; } public static void main(String[] args) { Collection<?>[] collections = { new Hashset<String>( ) , new ArrayList<Biglnteger>() , new HashMap<String, String>().values() }; for (Collection<?> c : collections) System.out.println(classify(c)); } }
Java
복사
위 코드를 보면 “집합”, “리스트”, “그 외” 순으로 출력할 것 같지만, 실제 “그 외”만 연달아 3번 출력한다.
그 이유는 다중정의된 세 메서드 중 어떤 메서드를 사용할 지는 컴파일 타임에 결정되는데, 컴파일 타임에 for 문 내의 c는 항상 Collections<?> 타입이기 때문이다.
이렇게 예상과 다른 동작을 하게 되는 이유는, Override한 메서드는 동적으로 선택되고 Overload한 메서드는 정적으로 선택되기 때문이다.

재정의 동작 방식

재정의는 해당 메서드를 가장 하위에서 재정의한 인스턴스 메서드가 실행된다.
class Wine { String name() { return "포도주"; } } class SparklingWine extends Wine { @Override String name() { return "발포성 포도주"; } } class Champagne extends SparklingWine { @Override String name() { return "샴페인"; } } public class Overriding { public static void main(String[] args) { List<Wine> wineList = List.of(new Wine(), new SparklingWine(), new Chmpagne()); for (Wine wine : wineList) System.out.println(wine.name()); } }
Java
복사
이 코드는 예상한 것과 동일하게 “포도주”, “발포성 포도주”, “샴페인” 순으로 출력된다.

다중정의가 혼동을 일으킬 때 문제 해결 방법

public static String classify(Collection<?> c) { return c instanceof Set ? "집합" : c instanceof List ? "리스트" : "그 외"; }
Java
복사
위의 문제가 있던 코드는 이렇게 작성하여 instanceof를 통해 명시적으로 검사하면 해결된다.
다중정의는 사용했을 때 혼동을 일으키는 상황을 피해야한다.
다중정의가 혼동을 일으키는 상황을 피하려면 몇 가지 방법이 있다.
안전하고 보수적으로 가려면 매개변수 수가 같은 다중정의를 만들지 않는 것도 하나의 방법이다.
다중정의하는 메서드들의 이름을 각자 다르게 지어 다중정의를 풀어내는 것도 고려하자.
생성자에서는 메서드의 이름을 다르게 설정하는게 불가능하니, 팩터리 메서드를 통해 해결하자.
매개변수의 수가 같더라도 두 타입이 근본적으로 달라 서로 형변환이 불가능하다면, 컴파일 타임에 어떤 다중 정의 메서드를 호출할지 영향을 받지 않는다.
특히 람다식을 매개변수로 넘기는 경우에는 다중정의를 더 신중하게 사용해야 한다. 다중정의된 메서드들이 함수형 인터페이스를 인수로 받는다면, 서로 다른 함수형 인터페이스더라도 같은 위치의 인수로 받게되면 컴파일 타임에 잘못 선택될 수 있기 때문이다.