마커 애너테이션 : 클래스, 메소드, 필드 등에 마킹하여 추가적인 정보를 제공하는 애터네이션.
주석처럼 사용되지만, 컴파일러나 런타임 환경에서 해당 요소들에 대한 특정한 동작을 유발할 수 있다.
컴파일러에게 문법 에러를 체크하도록 정보를 제공한다.
프로그램을 빌드할 때 코드를 자동으로 생성할 수 있도록 정보를 제공한다.
런타임에 특정 기능을 실행하도록 정보를 제공한다.
표준 애너테이션
//@Override 애너테이션
class Parent {
void display() {
System.out.println("Parent's display()");
}
}
class Child extends Parent {
@Override
void display() { // 컴파일러가 Parent의 display()가 존재하는지, 문법적 오류는 없는지 체크
System.out.println("Child's display()");
}
}
//프로그램 동작에는 직접적인 영향을 미치지 않지만,
//컴파일러나 프레임워크가 애너테이션을 이용하여 미리 오류를 잡아낼 수 있음
메타 애너테이션
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
// @Target 애너테이션을 사용하여 이 애너테이션이 클래스에만 적용될 수 있도록 함
@Target(ElementType.TYPE)
@interface ExampleClassAnnotation {
// 애너테이션 내용
String value();
}
// 애너테이션을 사용할 클래스
@ExampleClassAnnotation("This annotation is only applicable to classes")
class ExampleClass {
//메서드에는 사용 불가능(컴파일 오류 발생)
@ExampleClassAnnotation
void exampleMethod() {
System.out.println("I'm Groot");
}
}
//Serializable을 구현하지 않은 Item 클래스
class Item {
private long id;
private String name;
private BigDecimal price;
public Item(long id, String name, BigDecimal price) {
this.id = id;
this.name = name;
this.price = price;
}
}
public class test02 {
//직렬화하는 메서드를 만든다.
void serializableTest() throws IOException {
File f= new File("test.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(f));
objectOutputStream.writeObject(new Item(1L, "item A", new BigDecimal(30000)));
}
public static void main(String[] args) throws IOException {
test02 test= new test02();
//런타임 에러 발생(Item 클래스가 Serializable을 implement 하지 않으니까)
test.serializableTest();
//다만 컴파일 시점에서 에러를 잡아내지 못하기에
//마커 인터페이스를 제대로 구현해놓은 것은 아님
//컴파일 시점에서 에러를 잡지 못하는 이유는
//writeObejct 메서드가 Object를 매개변수로 받기 때문에
}
}
//그런데 여기서 Serializable 하지 않다는걸
//프로그래밍적으로 꼼꼼히 체크하는 것이 아니라
//그냥 Serializable에 상속되고있냐 아니냐 수준의
//타입 체크정도로만 사용한다
//위에서 Item implements Serializable 이렇게 바꾸면
//런타임 오류 안뜸
그럼 Serializable은 왜 어떤 메서드도 선언해놓지 않는가?
호환성 : Java 버전에 따라 구체적인 직렬화 방식이 달라질 수도 있기때문에
직렬화 가능 클래스가 명시적으로 선언해놓은 serialVersionUID를 통해 직렬화가 이루어짐
serialVersionUID가 선언돼있지 않다면 해당 클래스에 대한 기본 UID값을 계산
타입체크 용도 : 마커 인터페이스는 이를 구현한 클래스의 인스턴스들을 구분하는 타입으로 쓸 수 있으나,
마커 애너테이션은 그렇지 않다.
마커 애너테이션에 비해 적용 대상을 더 정밀하게 지정할 수 있다.
하지만, 마커 애너테이션은 거대한 애너테이션 시스템의 지원을 받는다.
애너테이션을 자주 활용하는 프레임워크라면
왠만하면 애너테이션을 써서 일관성을 지켜라
그러면 어떤 때에 마커 애너테이션을 쓰고, 마커 인터페이스를 써야하는가?
클래스와 인터페이스에 마킹을 해야할 때
마커 인터페이스를 쓰는 경우
마킹이 된 객체를 매개변수로 받는 메서드를 작성할 일이 있는 경우
그러면 컴파일 타입에 오류를 잡아낼 수 있다.
위 경우 말고는 마커 애너테이션을 쓰는 것이 낫다.
마커 인터페이스 사용 예시
//마커 인터페이스
interface MarkerInterface {
// 아무 메소드도 없음
}
//마커 인터페이스를 구현한 클래스
class MarkerClass implements MarkerInterface {
}
//마커 인터페이스를 구현하지 않은 클래스
class AnotherClass {
}
//특정 클래스
class MyClass {
// 특정 클래스의 생성자
public MyClass(MarkerInterface marker) {
// 생성자의 매개변수로 마커 인터페이스를 구현한 클래스만 허용
}
}
public class test03 {
public static void main(String[] args) {
// 올바른 인자 전달
MarkerClass markerObj = new MarkerClass();
MyClass myObj = new MyClass(markerObj);
// 잘못된 인자 전달
AnotherClass anotherObj = new AnotherClass();
// 컴파일 오류 발생
MyClass myObj2 = new MyClass(anotherObj);
}
}
클래스와 인터페이스 외의 프로그램 요소에 마킹을 해야할 때
클래스와 인터페이스 외의 프로그램 요소(모듈, 패키지, 필드, 지역변수 등)에 마킹을 해야할 때는 애너테이션을 쓸 수 밖에 없음
Chapter : 6. 열거 타입과 애너테이션
Item : 41. 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라
Assignee : jseok0917
🍑 서론
마커 애너테이션 : 클래스, 메소드, 필드 등에 마킹하여 추가적인 정보를 제공하는 애터네이션.
주석처럼 사용되지만, 컴파일러나 런타임 환경에서 해당 요소들에 대한 특정한 동작을 유발할 수 있다.
표준 애너테이션
🍑 본론
정의하려는 것이 타입이라면 마커 인터페이스를 사용하라
Serializable
본론 요약
마커 인터페이스와 마커 애너테이션의 차이
범위 :
세밀함 :
마커 인터페이스의 사용 용도 요약(책내용)
타입체크 용도 : 마커 인터페이스는 이를 구현한 클래스의 인스턴스들을 구분하는 타입으로 쓸 수 있으나,
마커 애너테이션은 그렇지 않다.
마커 애너테이션에 비해 적용 대상을 더 정밀하게 지정할 수 있다.
하지만, 마커 애너테이션은 거대한 애너테이션 시스템의 지원을 받는다.
그러면 어떤 때에 마커 애너테이션을 쓰고, 마커 인터페이스를 써야하는가?
클래스와 인터페이스에 마킹을 해야할 때
마커 인터페이스를 쓰는 경우
위 경우 말고는 마커 애너테이션을 쓰는 것이 낫다.
마커 인터페이스 사용 예시
🍑 결론
타입 체크가 필요하다면 마커 인터페이스를 사용해라
그 때를 제외하고는 마커 애너테이션을 사용해라
referenced by