class Wine {
String name() { return "Wine"; }
}
class SparklingWine extends Wine {
@Override String name() { return "SparklingWine"; }
}
class Champagne extends SparklingWine {
@Override String name() { return "Champagne"; }
}
public class Main {
public static void main(String[] args) {
List<Wine> wines = Arrays.asList(new Wine(), new SparklingWine(), new Champagne());
for (Wine wine : wines) {
System.out.print(wine.name() + " ");
}
}
}
// Wine SparklingWine Champagne
public class Main {
public static String classify(Set<?> set) {
return "집합";
}
public static String classify(List<?> list) {
return "리스트";
}
public static String classify(Collection<?> list) {
return "그 외";
}
public static void main(String[] args) {
Collection<?>[] collections = {
new HashSet<>(),
new ArrayList<>(),
new HashMap<String, String>().values()
};
for (Collection<?> c : collections) {
System.out.print(classify(c) + " ");
}
}
}
다중정의(오버로딩)된 classify 중 어느 메서드를 호출할 지 컴파일타임에 결정됨
→ 컴파일타임에 for 문 안의 c는 항상 Collection<?> 타입이므로 “그 외” 만 출력하게 됨
객체의 런타임 타입은 전혀 중요치 않고 매개변수의 컴파일타임 타입에 의해 선택이 이루어짐
매개변수의 런타임 타입에 따라 선택되게 하는 방법
public static String classify(Collection<?> c){
return c instanceof Set ? "집합" : c instanceof List ? "리스트" : "그 외";
}
→ 모든 classify 메서드를 하나로 합쳐 instanceof로 명시적으로 검사
매개변수 수가 같은 다중정의는 만들지 말자
다중정의 대신 메서드 이름을 다르게 지어주자
생성자는 이름을 다르게 지을 수 없어 두 번째 생성자부터는 다중정의를 할 수밖에 없게됨
→ 정적 팩터리 사용
매개변수 수가 같은 다중정의 메서드가 많더라도, 그중 어느 것이 주어진 매개변수 집합을 처리할지 명확히 구분될 수 있게 하자
→ 매개변수 중 하나 이상이 서로 어느 쪽으로든 형변환할 수 없다는 조건을 충족시키면 다중정의 메서드를 호출할지가 매개변수의 런타임 타입만으로 결정됨
ex) Collection을 받는 생성자와 int를 받는 생성자는 비록 매개변수의 수가 같지만, 절대 헷갈릴 일도 없을뿐더러 컴파일 타임에 의도치 않은 생성자로 동작할 우려가 없음
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++) {
set.add(i);
list.add(i);
}
for (int i = 0; i < 3; i++) {
set.remove(i);
list.remove(i);
}
System.out.println(set + " " + list);
}
}
//실행 결과 : [-3, -2, -1] [-2, 0, 2]
set.remove(i)의 시그니처는 remove(Object)
→ 다중정의된 다른 메서드가 없으니 집합에서 0 이상의 수들을 제거함