이번장의 핵심은...
프로그래밍 언어가 다중정의를 허용한다고 해서 다중정의를 꼭 활용하란 뜻은 아닙니다
일반적으로 매개변수 수가 같을 때는 다중정의를 피하는 게 좋습니다
다중정의 (overloading)
매개변수의 타입과 개수가 다르면서 이름이 같은 메서드를 여러개 가지는 것을 의미합니다
컴파일 타임에 어떤 메서드를 호출할지 정해집니다
// 코드 52-1 컬렉션 분류기 - 오류! 이 프로그램은 무엇을 출력할까?
public class CollectionClassifier {
public static String classify(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<BigInteger>(),
new HashMap<String, String>().values()
};
for (Collection<?> c : collections)
System.out.println(classify(c));
}
}
예상) "집합", "리스트", "그 외"
실제) "그 외", "그 외", "그 외"
다중정의는 컴파일 타임에 어떤 메서드를 호출할 지 정해지기 때문에 컴파일 타임엔 Collection<?> 타입이므로 "그 외"가 3번 출력됩니다
이 문제는 다중정의한 classify 메서드를 하나로 합친 후 instanceof로 명시적으로 검사하면 해결됩니다
public static String classify(Collection<?> c) {
return c instance of Set ? "집합" :
c instance of List ? "리스트" : "그 외";
}
재정의(Overriding)
상위 클래스의 메서드를 하위 클래스에 재정의하는 것을 의미합니다
런타임에 어떤 메서드를 호출할 지 정해집니다
// 코드 52-2 재정의된 메서드 호출 메커니즘 - 이 프로그램은 무엇을 출력할까?
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 Champagne());
for (Wine wine : wineList)
System.out.println(wine.name());
}
}
예상) "포도주", "발포성 포도주", "샴페인"
실제) "포도주", "발포성 포도주", "샴페인"
컴파일타임 타입은 Wine 이지만, 런타임시점 가장 하위에서 정의한 재정의 메서드가 실행됩니다
재정의한 메서드는 동적으로 선택되고, 다중정의한 메서드는 정적으로 선택
다중정의가 혼동을 일으키는 상황을 피하자
1. 안전하고 보수적으로 가려면 매개변수 수가 같은 다중정의는 만들지 말아야 합니다
2. 다중정의하는 대신 메서드 이름을 다르게 지어주는 길도 항상 열려있습니다
3. 생성자는 두번째부터 무조건 다중정의가 되는데 정적팩터리라는 대안이 있으니 적절히 사용합시다
ArrayList - remove()
list.remove(i) - remove(int index) / remove(Object) - 다중정의
(제네릭이 도입되기 전인 자바 4까지 List에서 Object와 int가 근본적으로 달라서 문제가 없었지만, 제네릭과 오토박싱이 등장하면서 두 메서드의 매개변수 타입이 더는 근본적으로 다르지 않습니다)
for (int i=0; i<3; i++) {
list.remove((Integer)i); // 값을 지움
// or list.remove(Integer.valueOf(i))
list.remove(i); // 인덱스를 지움
}
이 글은 “이펙티브 자바 3판” 책 내용을 정리한 글입니다.
만약 저작권 관련 문제가 있다면 “shk3029@kakao.com”로 메일을 보내주시면, 바로 삭제하도록 하겠습니다.
'Java > Effective Java 3E' 카테고리의 다른 글
[이펙티브자바 3판] ITEM54. null이 아닌, 빈 컬렉션이나 배열을 반환하라 (0) | 2021.01.16 |
---|---|
[이펙티브자바 3판] ITEM53. 가변인수는 신중히 사용하라 (0) | 2021.01.16 |
[이펙티브자바 3판] ITEM51. 메서드 시그니처를 신중히 설계하라 (0) | 2020.12.27 |
[이펙티브자바 3판] ITEM50. 적시에 방어적 복사본을 만들라 (0) | 2020.12.22 |
[이펙티브자바 3판] ITEM49. 매개변수가 유효한지 검사하라 (0) | 2020.12.19 |
댓글