마커 인터페이스

마커 애너테이션이 등장하면서 마커 인터페이스가 더 이상 쓸모없게 느껴질 수 있겠지만, 사실 마커 인터페이스는 두 가지 측면에서 마커 애너테이션보다 더 나은 점이 있다.

  1. 마커 인터페이스는 이를 구현한 클래스의 인스턴스들을 구분하는 타입으로 쓸 수 있으나, 마커 애너테이션은 그렇지 않다. 따라서 애너테이션을 사용하였다면 런타임에나 발견될 오류를 컴파일 타임에 잡을 수 있다.

    하지만, 자바의 Serializable 은 컴파일 타임 오류 검출의 장점을 살리지 못하였다.

    Untitled

    private void writeObject0(Object obj, boolean unshared)
            throws IOException
    {
        boolean oldMode = bout.setBlockDataMode(false);
        depth++;
        try {
            // (중략)
    
            // remaining cases
            // 실질적으로 뭘 하지 않고 간단히 Serializable가 선언되었는지 안되어 있는지 체크
            if (obj instanceof String) {
                writeString((String) obj, unshared);
            } else if (cl.isArray()) {
                writeArray(obj, desc, unshared);
            } else if (obj instanceof Enum) {
                writeEnum((Enum<?>) obj, desc, unshared);
            } else if (obj instanceof Serializable) {
                writeOrdinaryObject(obj, desc, unshared);
            } else {
                if (extendedDebugInfo) {
                    throw new NotSerializableException(
                            cl.getName() + "\\n" + debugInfoStack.toString());
                } else {
                    throw new NotSerializableException(cl.getName());
                }
            }
        } finally {
            depth--;
            bout.setBlockDataMode(oldMode);
        }
    }
    

    writeObject 메서드는 당연히 인수로 받을 객체가 Serializable 을 구현하였을 거라고 가정하지만, Object 객체를 받기 때문에, 직렬화할 수 없는 객체를 넘겨도 런타임에야 문제를 확인할 수 있다.

  2. 마커 인터페이스는 마커 애너테이션보다 적용 대상을 더 정밀하게 지정할 수 있다.

    @Retention(RetentionPolicy.RUNTIME) // 보존 정책
    @Target(ElementType.METHOD) // 적용 대상
    public @interface Test {
    }
    

    마크 애너테이션은 적용 대상( @Target )을 Element.Type 으로 선언한 애너테이션은 모든 타입(클래스, 인터페이스, 열거 타입, 애너테이션)에 달 수 있지만, 부착할 수 있는 타입을 더 세밀하게 제한할 수는 없다.

    반면, 마크 인터페이스는 그냥 마킹하고 싶은 클래스에서만 그 인터페이스를 구현하면 마킹된 타입은 자동으로 그 인터페이스의 하위 타입임이 보장된다.

반면, 마커 애너테이션이 더 나은 점은 거대한 애너테이션 시스템의 지원을 받는다는 것이다. 따라서 애너테이션을 적극 활용하는 프레임워크에서는 마커 애너테이션을 쓰는 것이 일관성을 지키는 데 유리할 것이다.

마커 애너테이션과 인터페이스의 기준?

결론

새로 추가하는 메서드 없이 단지 타입 정의가 목적이라면 마커 인터페이스를 정의하자.

클래스나 인터페이스 외의 프로그램 요소에 마킹해야 하거나, 애너테이션을 적극 활용하는 프레임워크의 일부로 마커를 편입시키고자 한다면 마커 애너테이션을 사용하자.