Item 52 : 다중정의는 신중히 사용하라
2021. 8. 20. 13:50
//컬렉션을 집합, 리스트 그외로 구분하기 위한 프로그램(오버로딩)
public class CollectionClassifier {
public static String classify(Set<?> s) {
return "Set";
}
public static String classify(List<?> lst) {
return "List";
}
public static String classify(Collection<?> c) {
return "그 외";
}
public static void main(String[] args) {
Collection<?>[] collections = {
new HashSet<>(),
new ArrayList<>(),
new HashMap<String, String>().values()
};
for (Collection<?> c : collections)
System.out.println(classify(c));
}
}
- 결과값은 "그 외"만 3번 출력된다.
- 다중정의(오버로딩)된 세 classify 중 어느 메소드를 호출할지가 컴파일 타임에 정해지기 때문이다.
- for문안에서 c는 항상 Collection<?>이기 때문에 세번째 메소드만 출력한다.
- 재정의한 메소드는 동적으로 선택되고 다중정의한 메소드는 정적으로 선택된다.
- 재정의 : Overriding
- 다중정의 : Overloading
//재정의한 메소드
class Wine {
String name() {
return "wine";
}
}
class SparklingWine extends Wine {
@Override
String name() {
return "sparkling wine";
}
}
class Champagne extends SparklingWine {
@Override
String name() {
return "champagne";
}
}
public class Overriding {
public static void main(String[] args) {
Wine[] wines = {
new Wine(), new SparklingWine(), new Champagne()
};
for (Wine wine : wines)
System.out.println(wine.name());
}
}
- wind, sparklingwine, champagne이 차례대로 출력됨
- 가장 하위에서 정의한 재정의 메소드가 실행되기 때문
- 반면 다중정의는 매개변수의 컴파일 타입에 의해 이뤄진다.
- 위의 classify를 다음과 같이 고치면 된다.
public static String classify(Collection<?> c) {
return c instanceof Set ? "집합" :
c instanceof List ? "리스트" : "그 외";
}
- 공개 API에서 사용자가 매개변수를 넘기면서 어떤 다중정의 메소드가 호추로딜지를 모른다면 프로그램이 오작동하기 쉬워진다.
- 안전하고 보수적으로 가려면 매개변수 수가 같은 다중정의는 만들지 말자
- 가변인수를 사용하는 메소드라면 다중정의를 아에 하면 안된다.(Item 53)
오토박싱 오류
- 오토박싱은 기본자료형을 래퍼로 감싸주지 않아도 자동으로 래핑되는 것을 의미한다.
public class SetList {
public static void main(String[] args) {
Set<Integer> set = new TreeSet<>();
List<Integer> list = new ArrayList<>();
for (int i = -3; i < 3; i++) {
//[-3, -2, -1, 0, 1, 2] 기대
set.add(i);
list.add(i);
}
for (int i = 0; i < 3; i++) {
//원소 0, 1, 2를 지우는 것을 기대
set.remove(i); //[-3, -2, -1] 출력
list.remove(i); //[-2, 0, 2] 출력
}
System.out.println(set + " " + list);
}
}
- set.remove(i)의 시그니처는 remove(Object) 라서 원소를 정확히 제거한다.
- list.remove(i)는 다중정의된 remove(int index)를 선택하기 때문에 인덱스 위치로 제거한다.
- list.remove( (Integer) i) 로 해주면 인자가 삭제된다.
정리
- 일반적으로 매개변수 수가 같을 때는 다중정의를 피하라
- 헷갈릴만한 매개변수는 형변환하여 정확한 다중정의 메소드가 선택되도록 해야 한다.
'책 > 이펙티브자바' 카테고리의 다른 글
Item 54 : null이 아닌, 빈 컬렉션이나 배열을 반환하라 (0) | 2021.08.22 |
---|---|
Item 53 : 가변인수는 신중히 사용하라 (0) | 2021.08.21 |
Item 51 : 메소드 시그니처를 신중히 설계하라 (0) | 2021.08.19 |
Item 50 : 적시에 방어적 복사본을 만들라 (0) | 2021.08.18 |
Item 49 : 매개변수가 유효한지 검사하라 (0) | 2021.08.17 |