프로그래밍 언어/Java

[Java] 어노테이션(annotation) 정리

happy_life 2022. 7. 2. 22:49

어노테이션(annotation) 정리

 

어노테이션이란?

프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것을 어노테이션이라고 한다. 주석처럼 프로그래밍 언어에 영향을 미치지 않으면서도 다른 프로그램에 유용한 정보를 제공하는 기능을 한다.

 

예를 들어, 소스 코드 중 특정 메서드만 테스트하기를 원하면 "@Test" 어노테이션을 붙여, 테스트 프로그램에 알리는 역할을 하지만 메서드가 포함된 프로그램 자체에 영향을 미치진 않는다.

 

@Test
public void method() {
}

 

표준 어노테이션

자바에서 기본적으로 제공하는 어노테이션이다.

어노테이션 설명
@Override 컴파일러에게 오버라이딩하는 메서드라는 것을 알린다.
@Deprecated 앞으로 사용하지 않을 것을 권고하는 대상에 붙인다.
@SuppressWarnings 컴파일러에게 특정 경고가 나타나지 않게 한다.
@SafeVarargs 제네릭 타입의 가변인자에 사용한다.
@FunctionalInterface 함수형 인터페이스임을 알린다.
@Native native메서드에서 참조되는 상수 앞에 붙인다.
728x90

@Override

부모의 메서드를 오버라이딩하는 메서드라는 것을 컴파일러에게 알리는 역할을 한다. @Override를 붙이면 컴파일러가 부모 클래스에서 같은 이름의 메서드가 있는지 확인하고 없으면 에러를 알려준다. 이를 통해 실수로 오버라이딩하는 메서드의 이름을 부모의 메서드와 다르게 입력하는 실수를 방지할 수 있다.

 

Parent의 method()를 오버라이딩하려하는 사진

 

예를 들어 Parent의 method를 Child에서 오버라이딩하려고 했는데, 아래와 같이 입력을 잘못하는 경우를 생각해보자. 이러한 경우에는 오버라이딩이 아닌 Child의 또 다른 메서드가 추가되는 것이다.  따라서 이러한 실수를 방지하기 위해 @Override 어노테이션을 사용한다. 이 어노테이션은 부모 메서드를 확인해 만약 입력한 메서드가 없는 경우 에러를 알려준다. 

meethod()가 parent에 없음

 

발생하는 에러

 

 

 

@Deprecated

JDK 버전이 올라가면서 새로운 것들이 추가되어도 구 버전의 코드를 함부로 삭제하기 어렵다. 그래서 더 이상 사용되지 않는 구버전의 코드에 @Deprecated 어노테이션을 붙여 "이 코드는 더이상 사용하지 않는 것을 권한다"라는 의미를 제공해준다. 예를 들어 Date는 JDK1.0 버전때 나왔던 오래된 코드이다. 이 클래스에는 @Deprecated된 것들이 많다.

Deprecated 어노테이션

 

@FunctionalInterface

 이 어노테이션을 붙이면 컴파일러가 "함수형 인터페이스"를 올바르게 선언했는지 확인한다. 함수형 인터페이스는 추상 메서드를 단 하나만 선언할 수 있다는 제약이 있는데 이러한 조건을 잘 지킬 수 있게 해준다.

 

 

@SuppressWarnings

경우에 따라서는 경고가 발생할 수 있는 경우에도 일단 묵인해야할 경우가 있는데, 이럴 때 사용한다. 아래의 예시를 보자.

 

제네릭스를 사용하라고 권장하는 경고

 

위와 같이 제네릭을 사용해야 하는 부분에 제네릭을 사용하지 않으면 경고가 발생한다. 이런 경고를 무시하고 싶다면 @SuppressWarnings 어노테이션을 사용하면 된다.

경고가 사라짐

 

 

여러개를 동시에 억제하고 싶다면 배열 형식을 한다.

@SuppressWarnings({"rawtypes", "deprecation"})

 

메타 어노테이션

어노테이션을 위한 어노테이션이다.

 

@Target

어노테이션이 가능한 대상을 지정할 때 사용된다.

SuppressWarningsd의 Target 어노테이션

 

SuppressWarnings 어노테이션을 TYPE, FIELD, METHOD 등에 붙여 사용할 수 있다는 것을 나타낸다.

대상 타입 의미
ANNOTATIONN_TYPE 어노테이션 타입
CONSTRUCTOR 생성자
FIELD 필드(멤버)
LOCAL_VARIABLE 지역 변수
METHOD 메서드
PARAMETER 파라미터
TYPE 타입(클래스, 인터페이스, ENUM)
TYPE_PARAMETER 타입 매개변수
TYPE_USE 타입이 사용되는 모든 곳
   

 

@Retention

어노테이션이 유지되는 기간을 정하는 데에 사용된다. 유지 정책은 아래 표를 보자.

유지 정책 의미
SOURCE 소스 파일에만 존재,  컴파일 까지
CLASS 클래스 파일에 존재, 실행시 사용 불가
RUNTIME 클래스 파일에 존재 런타임까지 사용 가능

 

@Documented

어노테이션에 대한 정보가 javadoc으로 작성된 문서에 포함되도록 한다. ( 잘 쓰진 않음)

 

@Inherited

어노테이션이 자식 클래스에 상속되도록 한다. 부모 클래스에 붙으면 자식 클래스도 어노테이션이 붙은 것처럼 인식하게 된다.

 

 

어노테이션 직접 만들기

어노테이션 규칙

 1. 요소의 타입은 기본형, String, enum, 어노테이션, Class만 허용된다.

2. 괄호 안에 매개변수를 선언할 수 없다.

3. 예외를 선언할 수 없다.

4. 요소를 타입 매개변수(제네릭) 으로 정의할 수 없다.

 

규칙 예시

 

사실 어노테이션을 직접 만드는 일은 거의 없으므로, 이런 것이 있다는 것 정도만 알면 된다.

 

어노테이션 요소

어노테이션은 @기호를 제외하면 인터페이스를 정의하는 것과 동일하다. 인터페이스와 비슷하게 상수를 정의할 순 있지만, 디폴트 메서드는 정의할 수 없다. (추상 메서드만 가능) 

 

아래의 코드를 보자

 

코드 예제 

@Retention(RetentionPolicy.RUNTIME) // 메타 어노테이션
@interface AnnoTest {
    int Count() default 1;
    String testedBy();
    String[] testTools();
}

위의 코드처럼 어노테이션 내에서 선언된 메서드를 "어노테이션 요소"라고 한다. Count(), testedBy(), testTools() 가 이에 해당한다. 어노테이션의 요소는 매개변수 없는 추상 메서드의 형태를 가지고 default로 값을 미리 지정해줄 수도 있다.

 

 

어노테이션 사용하기

어노테이션은 다음과 같이 사용할 수 있다.

 

코드 예제

@AnnoTest(testedBy = "kim", testTools = "Junit4, Junit5") //default는 안넣어줘도 됨
class AnnoUseClass {
}

어노테이션을 사용할 클래스에 위와 같이 요소와 값을 차례로 입력해 사용할 수 있다.

관행적으로 만약 요소가 하나이고 요소의 이름이 value() 라면 오소 이름을 생략하고 값만 넣어줄 수도 있다.

 

코드 예제

@Retention(RetentionPolicy.RUNTIME) // 메타 어노테이션
@interface AnnoTest2 {
    int value() ;
}

@AnnoTest2(5)
class AnnoUseClass2 {
}

 

 

이제 어노테이션에 입력된 값을 활용해보자. 역시 아래의 코드를 보면 이해가 빠를 것이다.

 

코드 예제

public class AnnotationEx2 {
    public static void main(String[] args) {
        // Class의 정보를 담은 class 객체 얻기
        Class<AnnoUseClass> annoUseClassClass = AnnoUseClass.class;

        // 어노테이션 정보 얻기
        AnnoTest annotation = annoUseClassClass.getAnnotation(AnnoTest.class);

        String testedBy = annotation.testedBy(); //"kim"
        String[] testTools = annotation.testTools();//"JUnit4, JUnit5"
    }
}

@Retention(RetentionPolicy.RUNTIME) // 메타 어노테이션
@interface AnnoTest {
    int Count() default 1;
    String testedBy();
    String[] testTools();
}


@AnnoTest(testedBy = "kim", testTools = "Junit4, Junit5") //default는 안넣어줘도 됨
class AnnoUseClass {
}

 

Class의 정보를 담은 class의 객체를 얻어오고 어노테이션 객체를 생성한다.

이 객체에서 기존의 요소를 받아오면 어노테이션에 들어있던 정보를 가져올 수 있다.