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

무한성장개발자·2025년 9월 25일

package me.whiteship.chapter08.item52;

import java.math.BigInteger;
import java.util.*;

// 코드 52-1 컬렉션 분류기 - 오류! 이 프로그램은 무엇을 출력할까? (312쪽)
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 타입으로만 실행이 된다.

package me.whiteship.chapter08.item52;

// 재정의된 메서드 호출 메커니즘 (313쪽, 코드 52-2의 일부)
class Wine {
    String name() { return "포도주"; }
}
package me.whiteship.chapter08.item52;

// 재정의된 메서드 호출 메커니즘 (313쪽, 코드 52-2의 일부)
class SparklingWine extends Wine {
    @Override String name() { return "발포성 포도주"; }
}
package me.whiteship.chapter08.item52;

// 재정의된 메서드 호출 메커니즘 (313쪽, 코드 52-2의 일부)
class Champagne extends SparklingWine {
    @Override String name() { return "샴페인"; }
}

각자 자기 자신이 구현한 것을 가져온다. 오버라이딩이다.

오버로딩은 작성하고 있는 컴파일 타입의 코드로 정의가 된다.

매개변수 수가 같을 때는 다중정의를 만들지 않는다.
가변인자도 다중정의를 만들지 않는다.
메서드 이름을 다르게 한다.

classifyCollection, classifyList 등등

생성자는 정적 팩토리를 사용하여 다중 정의를 최대한 피할 수가 있다.

package me.whiteship.chapter08.item52;

import java.math.BigInteger;
import java.util.*;

// 수정된 컬렉션 분류기 (314쪽)
public class FixedCollectionClassifier {
    public static String classify(Collection<?> c) {
        return c instanceof Set  ? "집합" :
                c instanceof List ? "리스트" : "그 외";
    }

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

instanceof 타입으로 체크할 수 있다.

package me.whiteship.chapter08.item52;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadExample {

    public static void main(String[] args) {
        new Thread(System.out::println).start();

        ExecutorService executorService = Executors.newCachedThreadPool();
//        executorService.submit(System.out::println);
    }
}

다른 함수형 인터페이스를 쓰더라도 다른 인터페이스를 쓰더라도 같은 위치에서 받으면 안된다.

이 떄는 컴파일러가 어떤 것을 맵핑해야 하는지 어렵다.
이 경우에는 이름을 submitRunnable, submitCallable로 하면 편했을 것 같다.

package me.whiteship.chapter08.item52;

public class StringExample {

    public static void main(String[] args) {
        String name = "keesun";
        name.contentEquals("keesun");
        name.contentEquals(new StringBuffer(name));

        char[] data = {'e', 'd', 'd'};
        System.out.println(String.valueOf((Object) data));
        System.out.println(String.valueOf(data));
    }
}


String.valueOf가 둘이 다른 일을 하는데 동일한 이름을 가지고 있다.
다중 정의를 사용하지 말고 그냥 이름을 다르게 하자.

0개의 댓글