// TYPE의 경우 모든 타입(클래스, 인터페이스, 열거 타입, 애너테이션)에 달 수 있다.
// 부착할 수 있는 타입을 더 세밀하게 제한하지는 못한다는 뜻이다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Developer {
}
@Developer
class Hoyeon {
}
public class MarkerAnnotationTest {
public static void main(String[] args) {
Class<?> testClass = Hoyeon.class;
if(testClass.isAnnotationPresent(Developer.class)) {
System.out.println("Developoer Annotation");
}
}
}
실행결과
Developoer Annotation
package java.io;
public interface Serializable {
}
/**
* 특정 인터페이스를 구현한 클래스에만 적용하고 싶은 마커가 있을 경우
* 이 마커를 인터페이스로 정의했다면, 그냥 마킹하고 싶은 클래스에서만 그 인터페이스를 구현하면 된다.
* 마킹된 타입은 자동으로 그 인터페이스의 하위 타입임이 보장되는 것이다.
*/
class SomeObject implements Serializable { // Serializable를 상속받지 않은 경우 java.io.NotSerializableException 발생
private String name;
private String email;
public SomeObject(String name, String email) {
super();
this.name = name;
this.email = email;
}
}
public class MarkerInterfaceTest {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
serializableTest();
}
public static void serializableTest() throws IOException, ClassNotFoundException {
File f = new File("a.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(f));
objectOutputStream.writeObject(new SomeObject("wonwoo", "test@test.com"));
}
}
마커 인터페이스는 적용 대상을 더 정밀하게 지정할 수 있다.
그렇다면 마커 어노테이션의 장점은 뭘까? 마커 어노테이션은 유연하게 확장이 가능하다. 어노테이션을 만들어 사용한 뒤에도 계속적으로 더 많은 정보를 추가할 수 있는 것이 큰 장점이다.
예를 들어, 어떤 어노테이션을 만들고 배포를 한 뒤에 뭔가 더 정보를 추가하고 싶다면 새로 추가된 요소들에 대해 default 값을 갖게 하면 하위 호환성도 지킬 수 있으면 처음에는 마커 어노테이션으로 시작하여 쓰다가 나중에는 기능이 많은 어노테이션으로 진화 가능하다.
하지만 인터페이스 경우에는 메소드를 만드는 순간 하위 호환성이 깨지므로 마커 어노테이션처럼 지속적인 진화는 불가능하다.
reference
https://woovictory.github.io/2019/01/04/Java-What-is-Marker-interface/