[아이템 52] 다중정의는 신중히 사용하라

Jimin Lim·2023년 7월 4일
0

Effective Java

목록 보기
35/38
post-thumbnail

아이템 52

다중정의는 신중히 사용하라

✅ Overloading 문제점

Overloading은 정의된 것 중, 어느 메서드를 호출할지는 컴파일타임에 정해진다. 즉, 런타임에는 타입이 매번 달라지지만 호출할 메서드를 선택하는 데는 영향을 주지 못한다는 것이다.

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 "Unknown Collection";
	}

	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));
		}
	}
}

위의 예시에서 HashSet, ArrayList, HashMap을 인자로 넘기고 있어 Set, List, Unknown Collection이 호출될 것 같지만 실제로는 Unknown Collection만 호출된다.

Overloading한 메서드는 정적으로 선택되는 반면, Override한 메서드는 동적으로 선택된다. 즉 하위에서 재정의하였다면 재정의된 메서드가 실행된다.

✅ Overloading 할 때의 주의점

매개변수 수가 같은 다중정의는 만들지 않는 것이 좋다. 차라리 메서드 이름을 다르게 짓는게 낫다. 생성자의 경우, 다중정의를 할 수 밖에 없다. 하지만 정적 팩터리를 사용해 의미있는 메서드로 정의할 수 있다.

만약 어떤 다중정의 메서드가 불리는지 몰라도 기능이 똑같다면 신경쓸 건 없다.

✅ 혼돈을 야기한 Overloading 예시

여러 생성자가 같은 수의 매개변수를 받아야 하는 경우, 매개변수 중 하나 이상이 근본적으로 다르다면 (서로 형변환 불가) 헷갈릴 일이 없다. 이 조건만 충족하면 어느 다중정의 메서드를 호출할지가 매개변수들의 런타임 타입만으로 결정된다. 따라서 컴파일타임 타입에는 영향받지 않을 수 있게 된다.

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);
}

위 코드에서 remove를 할 때, Set은 원소 값을 지우고 list는 인덱스에 해당하는 값을 지운다. list의 remove(Integer i)가 실제 원소 값을 지우는 것으로, Integer로 형변환한다면 remove(Object)를 호출해 원하는대로 0, 1, 2를 지울 수 있다.

(근본적으로 형변환이 가능해서 혼돈을 야기했다는 예시같다..)

profile
💻 ☕️ 🏝 🍑 🍹 🏊‍♀️

0개의 댓글