티스토리 뷰

아무 메서드도 담고 있지 않고, 단지 자신을 구현하는 클래스가 특정 속성을 가짐을 표시해주는 인터페이스를 마커 인터페이스 (marker interface)라 한다.

ex. Cloneable, Serializable

// 그냥 비어있음.
public interface Serializable {
}

 

마커 애너테이션의 예

ex. @Override, @FunctionalInterface, @SafeVarargs, @Native

 

Serializable 은 자신을 구현한 클래스의 인스턴스는 ObjectOutputStream 을 통해 쓸수(write) 있다고, 즉 직렬화(serialization) 할 수 있다고 알려준다.

 

마커 인터페이스는 두 가지 면에서 마커 애너테이션보다 낫다.

  1. 마커 인터페이스는 이를 구현한 클래스의 인스턴스들을 구분하는 타입으로 쓸 수 있으나, 마커 애너테이션은 그렇지 않다.
    1. 마커 인터페이스는 어엿한 타입이기에, 마커 애너테이션을 사용했다면 런타임에야 발견될 오류를 컴파일 타임에 잡을 수 있다.
  2. 적용 대상을 더 정밀하게 지정할 수 있다.
    1. 애노테이션의 경우 @Target 선언 으로 모든 타입에 달 수 있다.
    2. 부착 할 수 있는 타입을 더 세밀하게 제한하지는 못한다는 뜻이다.
    3. 근데 특정 인터페이스를 구현한 클래스에만 적용하고 싶은 마커가 있다고 치면, 이 마커를 인터페이스로 정의했다면 그냥 마킹하고 싶은 클래스에서만 그 인터페이스를 구현하면 된다.
    4. 마킹된 타입은 자동으로 그 인터페이스의 하위 타입임이 보장되는 것이다.

 

반대로 마커 애너테이션이 마커 인터페이스보다 나은점으로는 거대한 애너테이션 시스템의 지원을 받는다는 점이 있다.

따라서 애너테이션을 적극 활용하는 프레임워크에서는 마커 애너테이션을 쓰는 쪽이 일관성을 지키는데 더 유리할 것이다.

 

그렇다면 언제 마커 애너테이션을, 언제 마커 인터페이스를 사용하는가 ?

  • 클래스와 인터페이스 외의 프로그램 요소 (모듈, 패키지, 필드, 지역변수 등)에 마킹해야 할 때 애너테이션을 쓸 수 밖에 없다.
  • 마커를 클래스나 인터페이스에 적용해야 한다면 "이 마킹이 된 객체를 매개변수로 받는 메서드를 작성할 일이 있을까? " 를 자문해보자.
    • 그렇다 → 마커 인터페이스를 쓴다.
    • 마커 인터페이스를 해당 메서드의 매개변수 타입으로 사용하여 컴파일 타임에 오류를 잡아낼 수 있따.
    • 아니다 → 마커 애너테이션을 쓴다.
    • 추가로 애너테이션이 활발한 프레임워크라면 ? → 마커 애너테이션을 쓴다.

결론

  • 마커 인터페이스와 마커 애너테이션은 각자의 쓰임이 있다.
  • 새로 추가하는 메서드 없이 단지 타입 정의가 목적이면 마커 인터페이스를 쓰자.
  • 클래스나 인터페이스 외의 프로그램 요소에 마킹해야 하거나, 애너테이션을 적극적으로 쓰는 프레임워크라면 마커 에너테이션을 쓰자.
  • 적용 대상이 ElementType.TYPE 인 마커 애너테이션을 작성하고 있다면, 이게 정말 애너테이션으로 구현하는게 올흥ㄴ지, 혹은 인터페이스가 낫지는 않을지 곰곰이 생각해보자.