[Java] 자바의 정석 독서 #31 - 어노테이션

2025. 12. 31. 18:47·언어공부/Java | Kotlin

https://dev-dx2d2y-log.tistory.com/168

 

[Java] 자바의 정석 독서 #30 - 열거형

https://dev-dx2d2y-log.tistory.com/158 [Java] 자바의 정석 독서 #29 - 제너릭 메서드, 제너릭 형변환https://dev-dx2d2y-log.tistory.com/157 [Java] 자바의 정석 독서 #28 - 제너릭 와일드카드, 공변성어제 교보만 세 곳을

dev-dx2d2y-log.tistory.com

저번에는 열거형에 대해서 다뤘고, 이번에는 어노테이션에 대해서 다뤄보려한다.


Javadoc

JDK1.0부터 소스코드의 주석으로 HTML을 사용하는 Javadoc(javadoc.exe)이 있었다. 지금도 널리 사용되고 있고.

 

/**
 * The common interface extended by all annotation interfaces.  Note that an
 * interface that manually extends this one does <i>not</i> define
 * an annotation interface.  Also note that this interface does not itself
 * define an annotation interface.
 *
 * More information about annotation interfaces can be found in section
 * {@jls 9.6} of <cite>The Java Language Specification</cite>.
 *
 * The {@link java.lang.reflect.AnnotatedElement} interface discusses
 * compatibility concerns when evolving an annotation interface from being
 * non-repeatable to being repeatable.
 *
 * @author  Josh Bloch
 * @since   1.5
 */
public interface Annotation { ... }

Annotation 클래스에 적용된 javadoc 내용.

중간중간 '@' 태그들을 확인할 수 있는데 이 태그를 통해 주석 안에 정보를 저장하고, javadoc이 이 정보를 읽어서 문서를 작성하는데 사용된다. 이렇게 @ 태그를 사용하여 무언가를 알리거나, 정보를 알리는 용도로 사용된 것을 소스코드 내에서도 사용하기 시작한 것이 어노테이션이다.

 

/**
 * 컨트롤러
 */
@RestController
public class SendMessageToAIController { ... }

대표적으로 많이 사용되는 어노테이션인 스프링에서의 어노테이션 RestConroller.

위 어노테이션은 이 클래스가 RestController에 해당한다는 것과 스프링 컨테이너에 들어가야한다는 것만을 알려주고 프로그램 자체에는 어떠한 영향도 끼치지 않는다.

 

@Test
void method() { ... }

클래스 뿐 아니라 메서드에도 적용시켜 "이 메서드가 테스트용도로 사용됩니다."라는 것도 알릴 수 있다.

 

즉, @ 문자를 사용해 마치 주석처럼 프로그램에 아무 영향도 미치지 않고 단지 어떠한 목적이나 정보를 나타내기 위해 사용하는 것이 어노테이션이다.


표준 어노테이션

자바에서 기본적으로 제공하는 어노테이션들을 표준 어노테이션이라 칭한다.

 

@Override

오버라이드하고 있는 메서드 앞에서만 붙일 수 있다. 오버라이드된 메서드라는 것을 컴파일러에게 알려주는 역할을하며, 메서드 시그니처를 다르게 입력하는 등 제대로 상속되지 않으면 컴파일에러를 발생시킨다. 즉, 상속과정에서의 실수를 바로잡아주는 역할을 한다.

 

이펙티브자바에서도 이를 사용하라고 권장했다. 참고하도록.

 

@Deprecated

기존의 기능을 대체할 새 기능이 생겨도, 이미 기존 기능을 사용하고 있는 코드가 있을 수도 있다. 따라서 대체된 코드를 삭제하지 않고 더 이상 사용되지 않는 필드 또는 메서드에 @Deprecated를 붙여 사용하지 말 것을 권장한다. 물론 '권장'이기 때문에 사용하거나 말거나 개발자 자유긴한데 사용안하는것이 좋다.

 

@FunctionalInterface

람다를 사용할 때 함수형 인터페이스가 필요한데, 함수형 인터페이스는 몇 가지 제약이 필요하다. @FunctionalInterface 어노테이션은 이 인터페이스가 함수형 인터페이스라는 것과 컴파일과정에서 이 제약을 잘 지켰는지 확인하도록한다.

 

@SuppressWarnings

컴파일러가 보내는 경고메시지를 나타나지 않게 해준다. 대표적으로 위의 @Deprecated 어노테이션이 붙은 필드나 메서드를 사용하면 컴파일러가 경고메시지를 보내는데, 이 어노테이션을 사용하면 보여주지 않는다. 이외에도 unchecked(제너릭 타입 매개변수 미설정), rawtypes(제너릭 미사용), varargs(가변인자(개수가 변하는 매개변수)의 타입이 제너릭일 때)

 

@SuppressWarnings("deprecation")

위와같이 특정 경고를 무시할 수 있다. 여러 개 추가하고 싶다면 중괄호를 ( { ... } ) 로 지정해야한다.

 

@SafeVarargs

제너릭은 컴파일과정에서 타입이 소거되는데, 이러한 특성을 non-reifiable이라고한다. reifiable 타입에 대해서는 제너릭을 사용하지 않는 일반적인 클래스(제너릭이 붙지 않는 List, Comparator도 reifiable에 해당함)에 해당한다.

 

SafeVarargs 어노테이션의 기본 목적은 "가변인자가 non-reifiable하지만 타입안전하다'라는 것을 알려주기 위해서이다.

 

메서드에 가변인자를 넘겨주어야할 때 가변인자들이 non-refiable 타입인 경우, unchecked에러가 발생한다.

@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

Arrays에 정의된 asList() 메서드. 여기서 T는 제너릭(non-refiable)이자 가변인자다. 

 

https://dev-dx2d2y-log.tistory.com/158

 

[Java] 자바의 정석 독서 #29 - 제너릭 메서드, 제너릭 형변환

https://dev-dx2d2y-log.tistory.com/157 [Java] 자바의 정석 독서 #28 - 제너릭 와일드카드, 공변성어제 교보만 세 곳을 돌아다니면서 몇 가지 읽을만한 책을 봤다. 물론 거기에는 CS책도 포함되어있기도 했고.

dev-dx2d2y-log.tistory.com

자바의 정석 독서 #29

제너릭에 대해서 다룰 때 컴파일과정에서 타입이 제거된다고했다.

위에서 asList 메서드는 타입이 T (T extends Object)가 되므로 Object 타입으로 컴파일과정에서 바뀌게되고, ArrayList<Object>(a)가 된다. 그러면 ArrayList<>는 내부적으로 Object 배열을 만들게되므로 모든타입에 객체가 들어갈 수 있다. 그러면 제너릭을 사용하는 이유와, ArrayList<>의 한 타입만 받는 특성이 무너지므로 에러를 발생시키게된다.

 

하지만 asList에서 이미 제너릭을 사용하고있고, asList를 통해 만들어진 ArrayList<>는 값을 추가할 수 없으므로 결과적으로는 타입안전하다. 따라서 그 경고를 무시하기 위해 @SafeVarargs 어노테이션을 붙였다.

 

다만 @SafeVarargs는 "unchecked" 경고를 표시되지 않게할 수 있지만, varargs는 표시되지 않게 할 수 없기 때문에 보통은 @SuppressWarning 어노테이션을 같이 사용하는 편이다.


메타 어노테이션

메타 어노테이션은 어노테이션 내부에서 적용대상, 유지기간 등 어노테이션의 설정을 위해서 사용하는 어노테이션이다.

 

@Target

어노테이션의 적용대상을 정의한다. TYPE(클래스, 인터페이스, enum), TYPE_PARAMETER (타입 매개변수), FIELD(필드), CONSTRUCTOR(생성자) 등이 있다. 많으므로 필요할 때마다 확인하는 것도 좋다.

 

@Retention

어노테이션의 유지기간을 지정한다.

 

- SOURCE | 소스파일에만 존재하고 클래스파일에는 없음

@Override, @SuppressWarning처럼 컴파일러가 확인해야하는 경우에 해당한다.

 

- CLASS | 클래스 파일에 존재하지만 실행 중에서는 사용불가. 기본값

컴파일러가 클래스파일에 어노테이션 정보를 저장할 수 있으나 JVM이 이를 알지 못해 잘 사용되지 않는다. SOURCE 나 RUNTIME을 주로 사용한다고.

 

- RUNTIME | 실행시 사용 가능

@FunctionalInterface의 경우에는 컴파일러가 체크하지만 실행 시에도 사용되므로 여기에 해당한다.

 

@Documented

어노테이션의 정보가 javadoc으로 작성한 문서에 포함되도록한다.

 

@Ingerited

어노테이션이 하위클래스에 상속되도록한다. 이 어노테이션이 붙여진 어노테이션을 사용하면 하위클래스에도 적용된다.

 

@Repeatable

어노테이션은 보통 하나의 대상에 한 종류의 어노테이션을 사용하는데(여러 개를 사용하면 에러가 발생한다.), @Repeatable이 붙은 어노테이션의 경우에는 여러 번 사용할 수 있다.

 

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

이렇게 정의가 되어있다면 (커스텀 어노테이션을 사용하는 방법은 나중에 다룰 예정이다.)

 

@Todo("ToDoToDo")
@Todo("tOdOtOdO")
public static void main(String[] args) throws InterruptedException { ... }

이렇게 여러 개의 어노테이션을 부착할 수 있다.

 

@interface ToDos{
    Todo[] value();
}

여기서 ToDos는 여러 Todo 어노테이션을 하나로 묶어서 다룰 수 있는 어노테이션이다. Todo의 배열타입을 반드시 이름이 value가 되도록 설정해야한다.

 

왜 ToDos가 필요하냐면 자바는 하나의 대상에 동일한 타입의 어노테이션을 하나씩만 저장하도록 설계되어 어노테이션을 여러 개 사용할 수 없기 때문이다. 그래서 Todos를 사용해, 컴파일과정에서 @Todo 어노테이션들을 @Todo 어노테이션의 배열을 포함한 @ToDos 어노테이션으로 변경하고, 그 배열에 접근해 어노테이션들을 읽는다.

 

@ToDos({
    @Todo("ToDoToDo")
    @Todo("tOdOtOdO")
})
public static void main(String[] args) throws InterruptedException { ... }

컴파일과정에서 이렇게 변환되어서 @Todos 안의 배열에 접근해 @Todo 어노테이션들을 읽는 방식으로 어노테이션을 여러 개 적용시킬 수 있게되는 것이다.

 

@Native

@Native public static final long MIN_VALUE = 0x8000000000000000L;

네이티브 메서드에 의해 참조되는 상수필드를 나타낸다. 위는 Long 클래스에 정의된 @Native 어노테이션

말이 좀 어려운데 그냥 네이티브 메서드에서 참조할 상수를 선언해둔 것이다.

 

@IntrinsicCandidate
public native int hashCode();

네이비트 메서드는 JVM이 설치된 OS의 메서드다. 주로 C를 통해 작성되며, 자바에서는 메서드 선언부만 정의한다. 물론 이렇게 정의한 메서드와 OS의 메서드를 연결해주어야한다.

 

즉, @Native 어노테이션이 붙여진 변수는 해당 변수를 네이티브 메서드에서 사용하겠다는 의미와 동일하다.


커스텀 어노테이션 사용해보기

이번에는 어노테이션을 직접 만들어 사용해볼 것이다.

 

@interface 어노테이션이름 {
    ...내용...
}

기본형은 다음과 같다.

내용 부분에 메서드가 들어올 수 있는데, 이 메서드들을 요소라고 칭한다.

 

@interface TestInfo {
    int count();
    String testBy();
    DateTime testDate();
}

@interface DateTime {
    String yymmdd();
    String hhmmss();
}

이렇게. 각 내부 메서드들이 요소가 되며, 요소는 자신이 아닌 다른 어노테이션을 포함할 수 있다.

어노테이션을 설정할 때에는 인터페이스와 같이 메서드 선언부만 있는 추상메서드 형태로 선언된다.

 

@TestInfo(
    count = 1,
    testBy = "ColorIt",
    testDate = @DateTime(yymmdd = "251231", hhmmss = "180433")
)
public static void main(String[] args) throws InterruptedException

그리고 나중에 사용할 때 값만 빠짐없이 넣어주면 된다. 순서는 상관없다.

 

@interface TestInfo {
    int count() default 1;
    String testBy() default "ColorIt";
    DateTime testDate();
}

default 키워드를 사용해서 기본값을 지정할 수도 있다.

 

어노테이션 요소는

- 요소의 타입이 기본형, String, enum, 어노테이션, Class만 해당한다.

- 괄호 안에 매개변수 사용불가

- 예외처리 불가

- 제너릭을 사용할 수 없다.

등의 규칙을 지켜야한다.


마커 어노테이션

@Serializable이나 @Clonable 인터페이스처럼, 요소가 하나도 정의되지 않은 어노테이션이 있다. 이 어노테이션은 단지 특정한 용도를 알려주는 역할을 담당한다. 이를 마커 어노테이션이라고 칭한다.


이번에는 어노테이션에 대해서 알아보았다.

어노테이션은 개발자 또는 컴파일러가 해당 메서드, 변수, 클래스 등이 어떠한 기능을하는지 알려주는 역할을하며, 그 외에는 프로그램에 어떠한 역할을 끼치지 않는, 일종의 주석과도 비슷한 역할을 한다.

 

어노테이션 내부에서는 추상메서드를 선언할 수 있으며, (매개변수는 선언할 수 없다.) 선언된 메서드들은 default 설정이 되어있지 않는 이상 어노테이션을 사용하는 곳에서 메서드의 값을 지정해주어야한다.

'언어공부 > Java | Kotlin' 카테고리의 다른 글

[Java] 자바의 정석 독서 #30 - 열거형  (0) 2025.12.31
[Java] finalize()는 무엇이고, 왜 지양해야하는가?  (0) 2025.12.25
[Java] 자바 내에서 참조란 무엇인가?  (0) 2025.12.25
[Java] 자바의 정석 독서 #29 - 제너릭 메서드, 제너릭 형변환  (0) 2025.12.24
[Java] 자바의 정석 독서 #28 - 제너릭 와일드카드, 공변성  (1) 2025.12.23
'언어공부/Java | Kotlin' 카테고리의 다른 글
  • [Java] 자바의 정석 독서 #30 - 열거형
  • [Java] finalize()는 무엇이고, 왜 지양해야하는가?
  • [Java] 자바 내에서 참조란 무엇인가?
  • [Java] 자바의 정석 독서 #29 - 제너릭 메서드, 제너릭 형변환
Radiata
Radiata
개발을 합니다.
  • Radiata
    DDD
    Radiata
  • 전체
    오늘
    어제
    • 분류 전체보기 (211)
      • 신년사 (3)
        • 2025년 (2)
        • 2026년 (1)
      • CS (59)
        • JVM (12)
        • 백엔드 (20)
        • 언어구현 (1)
        • 객체지향 (1)
        • 논리회로 (5)
        • 컴퓨터구조 (9)
        • 데이터베이스 (1)
        • 컴퓨터 네트워크 (10)
      • 언어공부 (64)
        • Java | Kotlin (48)
        • JavaScript | TypeScript (9)
        • C | C++ (6)
      • 개인 프로젝트 (11)
        • [2025] Happy2SendingMails (3)
        • [2026] 골든리포트! (8)
        • [2026] 순수자바로 개발하기 (0)
        • 기타 이것저것 (0)
      • 팀 프로젝트 (29)
        • [2025][GDG]홍대 맛집 아카이빙 프로젝트 (29)
      • 알고리즘 (13)
        • 백준풀이기록 (11)
      • 놀이터 (0)
      • 에러 수정일지 (2)
      • 고찰 (24)
        • CEOS 23기 회고록 (2)
  • 블로그 메뉴

    • CS
    • 언어공부
    • 개인 프로젝트
    • 팀 프로젝트
    • 알고리즘
    • 고찰
    • 신년사
    • 컬러잇 개발블로그
  • 링크

    • 컬러잇 개발블로그
  • 공지사항

  • 인기 글

  • 태그

    144
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
Radiata
[Java] 자바의 정석 독서 #31 - 어노테이션
상단으로

티스토리툴바