요약
•
다중 정의의 문제점
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를 통해 명시적으로 검사하면 해결된다.
•
다중정의는 사용했을 때 혼동을 일으키는 상황을 피해야한다.
•
다중정의가 혼동을 일으키는 상황을 피하려면 몇 가지 방법이 있다.
◦
안전하고 보수적으로 가려면 매개변수 수가 같은 다중정의를 만들지 않는 것도 하나의 방법이다.
◦
다중정의하는 메서드들의 이름을 각자 다르게 지어 다중정의를 풀어내는 것도 고려하자.
◦
생성자에서는 메서드의 이름을 다르게 설정하는게 불가능하니, 팩터리 메서드를 통해 해결하자.
•
매개변수의 수가 같더라도 두 타입이 근본적으로 달라 서로 형변환이 불가능하다면, 컴파일 타임에 어떤 다중 정의 메서드를 호출할지 영향을 받지 않는다.
•
특히 람다식을 매개변수로 넘기는 경우에는 다중정의를 더 신중하게 사용해야 한다. 다중정의된 메서드들이 함수형 인터페이스를 인수로 받는다면, 서로 다른 함수형 인터페이스더라도 같은 위치의 인수로 받게되면 컴파일 타임에 잘못 선택될 수 있기 때문이다.