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 이상의 수들을 제거함