Java | Annotation

바다·2024년 4월 30일
0

Java

목록 보기
16/18
post-thumbnail

Annotation 이란?

  • 주석처럼 프로그래밍 언어에 영향을 미치지 않으며, 유용한 정보를 제공
  • 특정 프로그램에게 정보 제공을 위한 것
    • 예) @Test : 이 메소드가 테스트 대상임을 테스트 프로그램에게 알린다
      @Test   //JUnit에게 이게 Test라고 알려 줌
      public void method() {}

표준 Annotation

Java에서 제공하는 Annotation

어노테이션설명
@Override컴파일러에게 오버라이딩하는 메소드라는 것을 알린다
@Deprecated앞으로 사용하지 않을 것을 권장하는 대상에게 붙인다
@FunctionallInterface함수형 인터페이스라는 것을 알린다 (JDK 1.8)
@SuppressWarnings컴파일러의 특정 경고메시지가 나타나지 않게 해준다
@SafeVarags제네릭스 타입의 가변인자에 사용한다 (JDK 1.7)
@Nativenative 메소드에서 참조되는 상수 앞에 붙인다 (JDK 1.8)

@Override

  • 오버라이딩을 올바르게 했는지 컴파일러가 체크하게 한다
  • 오버라이딩 할 때 메소드 이름을 잘못 적는 실수를 하는 경우를 방지한다
class Child extends Parent {
    @Override
    void parentMethod() {}
}

@Deprecated

  • 앞으로 사용하지 않을 것을 권장하는 필드나 메서드에 붙인다
  • 더 나은 버전이 있으니, 사용하지 않을 것을 권장한다
  • 이 어노테이션이 붙은 메소드를 사용한다고 에러가 나는 것은 아님! 그냥 경고를 해 주는 것이다
@Deprecated
public int getDate() {
    return normalize().getDayOfMonth();
}

@FunctionalInterface

  • 함수형 인터페이스에 붙이면, 컴파일러가 올바르게 작성했는지 체크한다
  • 함수형 인터페이스에는 하나의 추상메소드만 가져야 한다는 제약이 있다
  • 추상메소드를 0개, 2개 이상 작성했을 때 컴파일러가 알려 준다
@FunctionalInterface
public interface Runnable {
    public abstract void run(); //추상 메서드
}

@SuppressWarnings

  • 컴파일러의 경고메시지가 나타나지 않게 억제한다
  • 괄호() 안에 억제하고자 하는 경고의 종류를 문자열로 지정한다
  • 두 개 이상의 경고를 동시에 억제할 수도 있다 {"deprecation", "unchecked", "varags"} 형태로 작성하기
import java.util.ArrayList;

@SuppressWarnings("unchecked")      //제네릭스와 관련된 경고를 억제
ArrayList list = new ArrayList();   //제네릭 타입을 지정하지 않았음
list.add(obj);                      //여기서 unchecked 경고가 발생

메타 Annotation

어노테이션을 위한 어노테이션!
어노테이션을 만들 때 사용한다

어노테이션설명
@Target어노테이션이 적용가능한 대상을 지정하는데 사용한다
@Documented어노테이션 정보가 javadoc으로 작성된 문서에 포함되게 한다
@Inherited어노테이션이 자손 클래스에 상속되도록 한다
@Retention어노테이션이 유지되는 범위를 지정하는데 사용한다
@Repeatable어노테이션을 반복해서 적용할 수 있게 한다 (JDK 1.8)

@Target

어노테이션을 정의할 때, 적용 대상 지정에 사용한다

@Retention

  • 어노테이션이 유지되는 기간을 지정하는데 사용한다
  • 컴파일러에 의해 사용되는 어노테이션(Override 등)의 유지 정책은 SOURCE 이다
  • 실행시에 사용 가능한 어노테이션(FunctionalInterface)의 유지 정책은 RUNTIME이다
유지 정책의미
SOURCE소스 파일에만 존재 / 클래스 파일에는 존재하지 않음
CLASS클래스 파일에 존재 / 실행시에 사용 불가 / 기본값
RUNTIME클래스 파일에 존재 / 실행시에 사용 가능
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target ({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

@Documented

  • javadoc으로 작성한 문서에 포함시키려면 @Documented를 붙인다

@Inherited

  • 어노테이션을 자손 클래스에 상속하고자 할 때, @Inherited를 붙인다
import java.lang.annotation.Inherited;

@Inherited                      //@SuperAnno가 자손까지 영향을 미치게 한다
@interface SuperAnno {}

@SuperAnno
class Parent{}

class Child extends Parent {}   //Child에 어노테이션이 붙은 것으로 인식한다

@Repeatable

  • 반복해서 붙일 수 있는 어노테이션을 정의할 때 사용한다
  • @Repetable이 붙은 어노테이션은 반복해서 붙일 수 있다
import java.lang.annotation.Repeatable;

@Repeatable(ToDos.class)
@interface Todo {
    String value();
}

@ToDo("delete test codes.")
@ToDo("override inherited methods")
class MyClass {
    
}
  • @Repetable인 @ToDo를 하나로 묶을 컨테이너 어노테이션도 정의해야 한다
@interface ToDos {      //여러 개의 ToDo 어노테이션을 담을 컨테이녀 어노테이션 ToDos
    ToDo[] value();     //ToDo 어노테이션 배열타입의 요소를 선언, 이름이 반드시 value이어야 함
}

마커 Annotation

  • 요소가 하나도 정의되지 않은 어노테이션
  • 따로 부여하는 값은 없지만, 이 어노테이션이 붙어있는 것만으로도 프로그램에게 정보를 제공한다
  • 예) Override, Test

어노테이션 직접 만들어 보기

기본 구조

@interface 어노테이션이름 {
    타입 요소이름();  //어노테이션의 요소를 선언한다
}
  • 어노테이션의 메소드는 추상 메소드이며, 어노테이션을 적용할 때 지정한다
  • 작성할 때 순서는 상관 없다
@interface TestInfo {
    int count();
    String testedBy();
    String[] testTools();
    TestType testType();    //Enum testType {FIRST, FINAL}
    DateTime testDate();    //자신이 아닌 다른 어노테이션을 포함할 수 있다
}

생성한 어노테이션 사용해보기

@TestInfo (
    count=3, testedBy="Kim",
    testTools={"JUnit", "AutoTester"},
    testType=TestType.First,
    testDate=@DateTime(yymmdd="240430", hhmmss="114040")
)
public class NewClass { ... }

어노테이션 요소의 규칙

어노테이션의 요소를 선언할 때, 아래의 규칙을 반드시 지켜야 한다

  • 요소의 타입은 기본형, String, enum, 어노테이션, Class만 허용
  • 괄호() 안에 매개변수를 선언할 수 없다
  • 예외를 선언할 수 없다
  • 요소를 타입 매개변수(Generic)로 정의할 수 없다

어노테이션의 요소

  • 적용시 값을 지정하지 않으면, 사용될 수 있는 기본값(default) 을 지정할 수 있다
@interface TestInfo {
    int count() default 1;  //기본값을 1로 지정
}

@TestInfo   //TestInfo(count=1)과 동일
public class NewClass { ... }
  • 요소가 하나이고, 이름이 value일 때는 요소의 이름을 생략할 수 있다
@interface TestInfo {
    String value();
}

@TestInfo("passed") //@TestInfo(value="passed")와 동일
public class NewClass { ... }
  • 요소의 타입이 배열인 경우, 괄호{} 를 사용해야 한다.
@Test(testTools={"JUnit", "AutoTester"})
@Test(TestTools={})     //요소가 없을 경우에는 빈 괄호라도 주어야 한다
profile
ᴘʜɪʟɪᴘᴘɪᴀɴs 3:14

0개의 댓글