목차
반응형

java 어노테이션이란?
Annotation : 주석이라는 사전적 의미를 가지고 있습니다.
java에서 어노테이션은 @를 붙여 코드에서 주석처럼 쓰이며, 동시에 컴파일 및 실행 시 여러 기능을 제공합니다.
사용자뿐만 아니라 프로그램에 추가 정보를 제공할 수 있으며, 이를 '메타 데이터'라고 부릅니다.
java 어노테이션의 기능과 효과
java 어노테이션은 아래와 같은 기능과 효과를 제공합니다.
- 메타 데이터 제공
- 컴파일 혹은 실행 시 특정 코드에 따른 기능을 제어 `ex: deprecated, override`
- 컴파일러에게 어노테이션에 따른 코드 작성에 대해 에러를 체크하거나 예외 처리
- 런타임에 특정 기능을 실행할 수 있도록 제어
- IDE 등에서 코드 작성 시 코드 자동 생성, 생성 보조 정보 제공 등 `ex: getter, setter`
- 컴파일 혹은 실행 시 특정 코드에 따른 기능을 제어 `ex: deprecated, override`
- 코드를 읽는 사람으로 하여금 주석과 같이 해당 코드에 대한 설명 제공
java 어노테이션의 종류
java 어노테이션은 크게 3가지로 분류됩니다.
- 빌트인 어노테이션 : Java.lang 내장 어노테이션으로 작성한 코드에 대한 컴파일러 제어 기능
- 종류 : `@Override, @Deprecated, @SuppressWarning, @FuntionalInterface`
- 메타 어노테이션 : 어노테이션 작성 및 정의를 위해 사용하는 어노테이션
- 종류 : ` @Target, @Retention, @Inherited, @Document, @Repeatable`
- 커스텀 어노테이션 : 사용자가 직접 작성하는 어노테이션
1. 빌트인 어노테이션의 사용 방법과 구현 예제
@Override
`@Override` 어노테이션은 자식 클래스 메서드가 부모 클래스 메서드를 재정의함을 의미합니다.
- 사용 시 해당 메소드의 메서드명과 매개변수 속성이 오버라이딩에 적합한지 컴파일러에서 확인합니다.
- 부모 클래스의 메소드를 오버라이딩 하는 경우에는 반드시 어노테이션을 명시할 수 있도록 합시다.
- 상위 클래스에서의 메소드의 오버로딩과 오버라이딩을 컴파일러가 정상적으로 구분할 수 있게끔 하기 위함
java
닫기/* Override */ class Parent{ void method(){ System.out.println("parent method"); } } class Child extends Parent { @Override // 해당 인자값과 메소드명이 부모 클래스와 일치한지 컴파일러가 확인 void method() { System.out.println("child method"); } }
@Override가 컴파일러 오류를 체크하는 경우
java
닫기/* Override */ class Parent{ void method(){ System.out.println("parent method"); } } class Child extends Parent { @Override // java: method does not override or implement a method from a supertype void method1() { // 메소드명이 불일치 System.out.println("child method"); } }
@Deprecated
더 이상 사용되지 않는다는 사전적 의미를 가진 어노테이션입니다.
- `@Deprecated` 어노테이션이 붙은 클래스, 메소드 등은 가급적 사용을 자제해 달라는 의미로 사용됩니다.
- `@Deprecated` 클래스나 메소드가 사용되거나 클래스를 상속, 메서드 오버라이드시 컴파일 과정에서 경고합니다.
java
닫기class Parent{ @Deprecated void method(){ System.out.println("parent method1"); } } class Child extends Parent { @Override void method() { // warning : Overrides deprecated method in Parent System.out.println("child method1"); } }

@SuppressWarnings
특정 컴파일 경고에 대해 인지하고 있으므로, 이를 사용하지 않도록 설정하는 것입니다.
- 두 가지 이상의 경고를 억제하기 위해서는 `@SuppressWarnings{("A", "B")}` 와 같이 묶어서 사용합니다.
- 경고를 억제하는 경우 그 이유에 대해 주석으로 부연 설명하는 것이 좋습니다.
- 대표적인 `@SuppressWarnings` 을 통한 경고 억제 종류
- `@SupressWarnings("all")` : 모든 경고를 억제합니다.
- `@SupressWarnings("deprecation")` : 사용하지 말아야 할 메서드 관련 경고를 억제합니다.
- `@SupressWarnings("finally")` : 반환하지 않는 finally 블럭 관련 경고를 억제합니다.
- `@SupressWarnings("unchecked')` : 검증되지 않은 연산자, 미확인 오퍼레이션 관련 경고를 억제합니다.
- `@SupressWarnings("rawtypes')` : 클래스의 매개변수 타입이 불특정 시 관련 경고를 무시합니다.
- `@SupressWarnings("unused')` : 미사용 코드 관련 경고를 무시합니다.
- `@SupressWarnings("null")` : 널 관련 경고를 억제합니다.
- `@SupressWarnings("cast")` : 형변환 관련 경고를 억제합니다.
- 구현 예시
java
닫기class Parent{ @SuppressWarnings("unused") // 미사용 코드 경고 억제 int unused; // 미사용 필드 unused } // ... 생략 ... public static void main(String[] args) { @SuppressWarnings("rawtypes") // 제너릭을 사용하는 클래스 타입 불특정 경고 억제 ArrayList list = new ArrayList(); }
@FunctionalInterface
인터페이스가 함수형 인터페이스임을 명시하며, 함수형 인터페이스 조건을 만족하는지 검증하는 어노테이션입니다.
- 함수형 인터페이스의 조건 : 인터페이스 내 한 개의 추상메소드만 존재해야 함
- 그래서 default나 static 메소드는 해당 인터페이스에 존재해도 상관없습니다. (비교적 지양할 것)
- 이러한 함수형 인터페이스는 익명 클래스 및 람다식 구현에 사용됩니다.
java
닫기@FunctionalInterface // error : 함수형 인터페이스에서 2개 이상의 추상 메소드 사용 불가 interface FItest{ void absmethod1(); void absmethod2(); }
interface FItest{ // 함수형 인터페이스에 한 개의 추상메소드만 존재 가능하다 void absMethod1(); static void sttMethod(){ // static 메소드 System.out.println("static method"); } default void dftMethod(){ // default 메소드 // 인터페이스 내부의 default 메소드는 명시적으로 default로 선언해야 한다 System.out.println("default method"); } }
2. 메타 어노테이션별 커스텀 어노테이션 구현 방법과 예제
메타 어노테이션은 어노테이션을 직접 커스터마이징하고 생성 할 수 있는 기능을 제공합니다.
메타 어노테이션별 기능을 단계적으로 예제에 적용해보며 알아보겠습니다.
@interface
@interface는 사용자가 정의한 커스텀 어노테이션임을 정의합니다.
java
닫기/* Custom Annotation */ @interface CustomAnnotation { }
@Target
@Target은 어노테이션을 적용할 수 있는 대상을 지정합니다.
- 지정할 수 있는 옵션
- 복수 지정 시 `@Target({ElementType.METHOD, ElementType.PARAMETER})` 와 같은 형태로 묶어 사용합니다.
- `@Target(ElementType.TYPE)` : 기본값, 클래스의 어떤 요소에나 적용 가능
- `@Target(ElementType.FIELD)` : 클래스의 필드
- `@Target(ElementType.METHOD)` : 클래스의 메서드
- `@Target(ElementType.PARAMETER)` : 메서드 인자값
- `@Target(ElementType.TYPE_PARAMETER)` : 제네릭과 같은 타입 매개변수
- `@Target(ElementType.CONSTRUCTOR)` : 클래스 생성자
- `@Target(ElementType.LOCAL_VARIABLE)` : 클래스 지역변수
- `@Target(ElementType.ANNOTATION_TYPE)` : 어노테이션 타입
- 예제
java
닫기@Target({ElementType.METHOD, ElementType.FIELD}) // 지정할 수 있는 옵션을 메소드, 필드로 한정 @interface CustomAnnotation {} @CustomAnnotation // error : 클래스는 지정할 수 있는 옵션이 아님 class testTargetAnnotation { @CustomAnnotation int local; @CustomAnnotation void method(){}; }
@Retention
@Retention은 어노테이션의 수명 주기를 지정합니다.
- 수명 주기 짧은 순 → 긴 순 : SOURCE(. java 파일까지) → CLASS(. class 파일까지) → RUNTIME(실행 중에도)
- 지정할 수 있는 옵션
- `@Retention(RetentionPolicy.SOURCE)` :. java 소스 파일까지 어노테이션이 적용되게끔 설정합니다.
- 컴파일 이후에는 사라집니다.
- ex) `@Override, @Getter, @Setter` 등이 있습니다.
- `@Retention(RetentionPolicy.CLASS)` : 컴파일 이후. class 파일까지 어노테이션이 적용되게끔 설정합니다.
- 런타임에는 사라집니다.
- ex) Lombok의 `@NonNull` 등이 있습니다.
- `@Retention(RetentionPolicy.RUNTIME)`: 런타임에도 JVM에 남아 어노테이션이 참조될 수 있게 설정합니다.
- ex) `@Deprecated` 등이 있습니다.
- `@Retention(RetentionPolicy.SOURCE)` :. java 소스 파일까지 어노테이션이 적용되게끔 설정합니다.
@Documented
@Documented은 javadoc에서 해당 어노테이션을 표기할지 여부를 결정합니다.
- 인텔리제이에서 javadoc export 하는 방법
1. `shift + shift (search anything)` 으로 들어간 뒤 Generate JavaDoc 검색 후 클릭
2. File은 export 할 파일, 지정 디렉터리는 해당 패키지가 있는 디렉터리로 지정
3. `Visibility Level` : 어느 제어자까지 javadoc에 표기할 것인지를 묻는 것이므로 확인하고자 하는 메서드 혹은 클래스의 선언부를 확인 후 기재
4. `Command line Arguments` : `-encoding UTF-8 -charset UTF-8 -docencoding UTF-8` 기입\
5. `Generate`로 생성 후 해당 디렉터리에서 `index.html` 실행
- @Documented 적용 / 미적용 차이 확인
java
닫기/** * Documented을 적용 여부를 확인할 사용자 정의 어노테이션(현재는 미적용 상태) */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface CustomAnnotation { String s(); } /** * Document 적용 여부에 따른 JavaDoc 차이를 확인한다. */ @CustomAnnotation(s = "document test") public static void testDocument() { } public static void main(String[] args) { testDocument(); }


Documented가 적용된 어노테이션을 사용 시 Javadoc에 사용된 어노테이션이 같이 표기됨을 확인했습니다.
@Repeateable
@Repeatable : 연속적으로 중복 정의가 가능하게끔 어노테이션을 사용할 수 있게 설정합니다.
구현 예시 (Repeatable을 사용하지 않은 어노테이션의 value 값 복수 정의)
java
닫기 public @interface CustomAnnotation { String[] value(); } @CustomAnnotation({"Hi", "Hello", "How are you"}) public static void testRepeatable(){ }
구현 예시 (Repeatable을 사용해 중복 어노테이션 사용을 통한 value 값 복수 정의)
java
닫기// Repetable을 적용할 어노테이션 @Documented @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Repeatable(CustomAnnotationContainer.class) // Repeatable을 적용하기 위해 위에서 만든 컨테이너.class를 반복한다고 @Repeatable 명시한다 public @interface CustomAnnotation { String value() default ""; } // 컨테이너 어노테이션 : 묶고자 하는 어노테이션을 배열로 멤버로 만든다 // * 컨테이너 어노테이션의 메타 어노테이션 제한은 묶을 어노테이션과 동일해야 함 @Documented @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface CustomAnnotationContainer { CustomAnnotation[] value(); // 묶고자 하는 CustomAnnotation을 배열로 멤버 선언 } // Repetable이 적용된 어노테이션의 사용 예시 @CustomAnnotation("Hi") @CustomAnnotation("Hello") @CustomAnnotation("How are you") public static void testRepeatable(){}
Q. 이렇게 따로따로 Repeatable을 사용해 value를 명시하는 이유가 뭐일까요?
A. 어노테이션이 여러 값을 받는 속성인 경우 가독성 면에서 별도로 명시하는 것이 용이할 수 있기 때문입니다.
또한 @Test (value1 = 1, value2 = "aaa", value 3 = false)와 같은 형태로 여러 멤버를 명시해야 한다면
더더욱이 어노테이션을 중복 선언하는 것이 코드를 짜는 입장에서 보기 편할 것입니다.
#구현 코드
반응형
'DEV > Java' 카테고리의 다른 글
[java] JVM 메모리 구조와 변수별 메모리 할당 (0) | 2023.10.23 |
---|---|
[java] 스트림 도전기 (2 / 3) - 람다식, java.util.function (2) | 2023.10.18 |
[java] Comparable 활용 Collections.sort() 정렬 방식 정의 (0) | 2023.10.12 |
[java] 중첩 클래스(Nested Class)의 이해와 구현 (1) | 2023.10.09 |
[java] 코딩테스트 대비 java 클래스 별 메소드 정리 (2 / 2) (0) | 2023.10.05 |