개발하는 두더지

[Effective Java 규칙41] 오버로딩할 때는 주의하라 본문

Java,Android

[Effective Java 규칙41] 오버로딩할 때는 주의하라

덜지 2018. 10. 15. 18:26

[Effective Java 규칙41] 오버로딩할 때는 주의하라

Effective Java 2/E 책과 구글링을 통해 내용을 정리하고 개인적인 견해가 포함된 글입니다.



아래는 컬렉션을 종류별로 (집합, 리스트, 다른 종류의 컬렉션) 분류하는 클래스이다.

public class CollectionClassifier {
public static String classify(Set<?> s) { return "SET"; }
public static String classify(List<?> s) { return "LIST"; }
public static String classify(Collection<?> s) { return "UNKNOWN COLLECTION"; }

public static void main(String[] args) {
Collection<?>[] collection = {
new HashSet<String>(),
new ArrayList<Integer>(),
new HashMap<String, Integer>().values()
};

for(Collection<?> c : collection)
System.out.println(CollectionClassifier.classify(c));
}
}

SET, LIST, UNKNOWN COLLECTION을 순서대로 호출할 것 같지만 UNKNOWN COLLECTION를 3번 호출한다. classify 메서드는 오버로딩되어있고, 오버로딩된 메서드 중 어느것이 실행될지는 컴파일 시점에 결정되기 때문에 마지막 classify가 3번 호출되는 것이다.

인자로 들어가는 객체는 실행 시점에 전부 다른 자료형이지만 메서드의 인자는 컴파일 시점에 Collection<?> 타입으로 결정되었다.

즉, 컴파일 시점의 자료형이 영향을 주고, 실행 시점의 자료형은 영향을 주지 않는다.


오버로딩된 메서드는 정적으로 선택되지만 재정의된 메서드는 동적으로 선택된다. 재정의된 메서드의 경우, 선택 기준은 메서드의 호출 대상 객체의 자료형이다. 객체 자료형에 따라 실행 도중에 결정되는 것이다.

class Wine {
String name() { return "Wine"; }
}

class SparklingWine extends Wine {
@Override
String name() { return "SparklingWine"; }
}

class Champagne extends Wine {
@Override
String name() { return "Champagne"; }
}

public class Overriding {
public static void main(String[] args) {
Wine[] wine = {
new Wine(),
new SparklingWine(),
new Champagne()
};

for(Wine w : wine)
System.out.println(w.name());
}
}

Wine, SparklingWine, Champagne 이 순서대로 출력된다. 컴파일 시점의 자료형이 영향을 주지 않고 , 실행 시점의 자료형이 영향을 준다.


CollectionClassifer를 통해 확인할 수 있듯이, 오버로딩을 사용할 때는 혼란스럽지 않게 사용하도록 주의해야 한다. 오버로딩된 메서드 가운데 어떤 것이 주인자를 처리할지 알기 어려운 API는 가능하면 피해야 한다. 혼란을 피하는 가장 좋은 방법은 같은 수의 인자를 갖는 2개의 오버로딩 메서드를 API에 아예 추가하지 않는 것이다.




















Comments