도도한 개발자

[Java] #17. Annotation (어노테이션) 본문

Backend/Java

[Java] #17. Annotation (어노테이션)

Kiara Kim 2022. 3. 26. 18:00

* Annotation 이란?

 

어노테이션은 클래스나 메소드 등의 선언시에 @를 사용하는 것을 말한다. 어노테이션은

 

· 컴파일러에게 정보를 알려주거나

· 컴파일할 때와 설치(deployment)시의 작업을 지정하거나

· 실행할 때 별도의 처리가 필요할 때

 

사용한다. 이와 같이 다양한 용도로 사용할 수 있는 어노테이션은 클래스, 메소드 변수 등 모든 요소에 선언할 수 있다.

 

 

* 미리 정해져 있는 3개의 어노테이션

 

자바 언어에는 어노테이션을 선언하기 위한 4개의 메타 어노테이션과, 일반적으로 사용 가능한 어노테이션이 3개가 있다.

 

· @Override

· @Deprecated

· @SuppressWarnings

 

위 3개의 어노테이션에 관해 살펴보자.

 

** @Override

 

해당 메소드가 부모 클래스에 있는 메소드를 Override 했다는 것을 명시적으로 선언한다. "이 메소드는 Override 된 거니까 만약 내가 잘못 코딩했으면 컴파일러 니가 알려줘야 해" 라고 지정해 주는 것이라고 생각하면 된다.

 

예제를 통해 알아보자. 10장에서 사용한 Parent 클래스를 보자.

 

public class Parent {
	public Parent() {
		System.out.println("Parent Constructor");
	}
    public Parent(String name) {
		System.out.println("Parent(String) Constructor");
	}
	
	public void printName() {
		System.out.println("Parent printName()");
	}
}

 

Parent 클래스를 확장하는 AnnotationOverride라는 클래스를 만들자. 그리고 Parent 클래스에 선언되어 있는 printName() 메소드를 Override하자.

 

public class AnnotaionOverride extends Parent{
	@Override
	public void printName() {
		System.out.println("AnnotationOverride");
	}
}

 

위의 코드를 보면 printName() 이라는 Parent클래스의 메소드를 AnnotationOverride 클래스에서 Override 했다. 만약 AnnotationOverride 클래스에 아주 많은 메소드들이 선언되어 있다면, 어떤 메소드가 부모 클래스에 있는 것을 Override 했는지 알아보기 힘들 것이다. 따라서 이렇게 @Override 어노테이션을 추가해주면 쉽게 확인이 가능하다.

 

 

** @Deprecated

 

미리 만들어져 있는 클래스나 메소드가 더 이상 사용되지 않는 경우가 있다. 그런 것은 deprecated라고 하는데, 컴파일러에게 "얘는 더 이상 사용하지 않으니까 그렇게 알아줘. 그리고 나중에 누가 이거 쓰면 경고 한 번 해주고" 라고 알려주는 것이라고 생각하면 된다.

 

예제를 통해 알아보자. AnnotationDeprecated 클래스에 noMoreUse라는 Deprecated 된 메소드를 만들자.

 

public class AnnotationDeprecated {
	@Deprecated
	public void noMoreUse() {
		
	}
}

 

그리고 AnnotationSample 클래스를 만들어 이 메소드를 호출하는 useDeprecated() 라는 메소드를 추가하자.

 

public class AnnotationSample {
	public void useDeprecated() {
		AnnotationDeprecated child = new AnnotationDeprecated();
		child.noMoreUse();
	}
}

 

이렇게 Deprecated 된 메소드를 컴파일하면 컴파일에 "경고"만 있을 뿐 "에러"는 없다. 때문에 클래스 파일은 생성되어 있을 것이다. 

 

 

** @SupressWarnings

 

코딩을 하다 보면 컴파일러에서 경고를 알리는 경우가 있다. 그럴 때 컴파일러에게 "얘는 내가 일부러 이렇게 코딩한 ㅓ니까 니가 경고를 해 줄 필요가 없어"라고 얘기해 주는 것이다.

 

예제로 알아보자. 아래와 같이 useDeprecated라는 메소드에 어노테이션을 추가해보자.

 

public class AnnotationSample {
	@SuppressWarnings("deprecation")
	public void useDeprecated() {
		AnnotationDeprecated child = new AnnotationDeprecated();
		child.noMoreUse();
	}
}

 

이 어노테이션은 지금까지의 어노테이션과 다르게 소괄호 속에 문자열을 넘겨주었다. 이렇게 어노테이션의 종류에 따라 속성값을 지정하는 것도 존재한다. 그러나 이 어노테이션을 너무 남용할 경우 Deprecated된 메소드를 사용해도 모르고 넘어갈 수 있으니 주의해야 한다.

 

 

* 어노테이션을 선언하기 위한 메타 어노테이션

 

메타 어노테이션은 어노테이션을 선언할 때 사용한다. 다음과 같이 4개가 존재한다.

 

· @Target

· @Retention

· @Documented

· @Inherited

 

각각에 대해 알아보자.

 

** @Target

 

어노테이션을 어떤 것에 적용할지 선언할 때 사용한다. 적용 방법은 다음과 같다.

 

@Target(ElementType.METHOD)

 

이처럼 @Target괄() 호 안에 적용 대상을 지정하는데, 그 목록은 다음과 같다.

 

요소 타입 대상
CONSTRUCTOR 생성자 선언시
FIELD enum 상수를 포함한 필드(field) 값 선언시
LOVAL_VARIABLE 지역 변수 선언시
METHOD 메소드 선언시
PACKAGE 패키지 선언시
PARAMETER 매개 변수 선언시
TYPE 클래스, 인터페이스, enum 등 선언히

 

 

** @Retention

 

얼마나 오래 어노테이션 정보가 유지되는지를 다음과 같이 선언한다.

 

@Retention(RetentionPolicy.RUNTIME)

 

괄호 안에 지정하는 적용 가능 대상은 다음과 같다.

 

대상
SOURCE 어노테이션 정보가 컴파일시 사라짐
CLASS 클래스 파일에 있는 어노테이션 정보가 컴파일러에 의해 참조 가능함. 하지만 가상 머신에서는 사라짐
RUNTIME 실행시 어노테이션 정보가 가상 머신에 의해 참조 가능

 

 

** @Documented

 

해당 "어노테이션에 대한 정보가 Javadocs(API)문서에 포함된다는 것"을 선언한다.

 

 

** @Inherited

 

모든 자식 클래스에서 부모 클래스의 어노테이션을 사용 가능하다는 것을 선언한다.

 

 

* 어노테이션을 선언해 보자.

 

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)	// 1
@Retention(RetentionPolicy.RUNTIME)	// 2
public @interface UserAnnotation {	// 3
	public int number();	// 4
	public String text() default "This is first annotation";	// 5
}

 

가장 먼저, import한 클래스를 보자. 어노테이션 관련 클래스들은 java.lang.annotation 패키지에 선언되어 있다.

 

1 : @Taret은 해당 어노테이션 사용 대상을 지정한다. 여기선 ElementType.METHOD를 소괄호 안에 넣어 줌으로써 이 어노테이션은 메소드에 사용할 수 있다고 지정된 것이다.

2 : @Retention은 어노테이션 유지 정보를 지정하는 데 사용한다. 소괄호 안에 RetentionPolicy.RUNTIME으로 지정하면 실행시에 이 어노테이션을 참조하게 된다.

3 : 어노테이션 이름인 UserAnnotation 앞에는 @inteface가 선언되어 있다. 처음 보면 익숙하지 않겠지만, 클래스나 인터페이스를 선언할 때처럼 @interface로 선언하면 @UserAnnotation으로 어노테이션이 사용 가능해진다.

4 : 어노테이션 선언 안에는 number() 라는 메소드와 text()라는 메소드가 있다. number()의 리턴 타입은 int이며, text() 의 리턴 타입은 String이다. 이렇게 메소드처럼 어노테이션 안에 선언해 놓으면, 이 어노테이션을 사용할 때 해당 항목에 대한 타입으로 값을 지정 가능하다.

5 : text()를 보면, default라는 예약어를 쓴 뒤 문자열이 지정되어 있는 것을 볼 수 있다. default예약어를 사용할 경우에는, default 뒤에 있는 값이 이 어노테이션을 사용할 때의 기본값이 된다. 즉, 값을 지정하지 않아도 default 값으로 지정된다.

 

그러면 만든 @UserAnnotaion을 사용하는 클래스 예제를 보자.

 

public class UserAnnotationSample {
	@UserAnnotation(number = 0)

	public static void main(String[] args) {
		UserAnnotationSample sample = new UserAnnotationSample();
	}
	
	@UserAnnotation(number = 1)
	public void annotationSample1() {
		
	}
	@UserAnnotation(number = 2, text = "second")
	public void annotationSample2() {
		
	}	@UserAnnotation(number = 3, text = "third")
	public void annotationSample3() {
		
	}
}

 

이렇게 메소드를 선언할 때 직접 만든 어노테이션을 사용할 수 있다. 어노테이션 선언 클래스에 지정해 놓은 각 메소드의 이름에 해당하는 값을 소괄호 안에 넣어 주어야만 한다. 

 

 

* 상속이 안되는 어노테이션

 

자바의 상속은 많은 이점을 제공하지만, 앞서 살펴본 enum 클래스가 상속을 지원하지 않듯, 어노테이션을 선언할 때에서 미리 만들어 놓은 어노테이션을 확장하는 것이 불가능한다. 어노테이션은 용도에 따라 다음과 같이 나눌 수 있다.

 

· 제약사항 등을 선언하기 위해 : @Deprecated, @Override, @NotNull

· 용도를 나타내기 위해 : @Entity, @TestCase, @WebService

· 행위를 나타내기 위해 : @Statefull , @Transaction

· 처리를 나타내기 위해 : @Column, @XmlElement

 

어노테이션이 만들어지면서 각 설정이 필요한 위치에 관련 설정이 존재하면서 코드에 대한 가독성이 매우 좋아졌다. 어노테이션을 직접 선언하여 개발할 일은 거의 없지만 이미 만들어져 있는 어노테이션을 사용하는 방법은 알고 있어야만 한다. 어노테이션을 지정하면 코드가 내부적으로 어떻게 변환되는지에 대해 살펴보는 습관을 가지는 것이 좋다.

 

 

* 정리

 

@Override 어노테이션의 용도는 무엇인가요?
메소드가 부모 클래스에 있는 메소드를 Override했다는 것을 명시적으로 선언할 때 @Override 어노테이션을 사용한다. 이 어노테이션을 사용하는 가장 큰 이유는 해당 메소드 선언이 정확히 부모 클래스를 Override했는지를 확인하기 위함이며, 다른 개발자가 해당 코드를 보고 쉽게 이해할 수 있도록 하는 이유도 존재한다.

@SupressWarnings 어노테이션의 용도는 무엇인가요? 
@SupressWarnings 어노테이션은 컴파일시 발생 할 수 있는 경고(warning)을 컴파일러에게 이야기 해 주는 것이다. 따라서, 반드시 사용할 필요는 없다.

@Deprecated 어노테이션의 용도는 무엇인가요? 
더 이상 사용하지 않는 메소드를 선언 앞에 @Deprecated 를 사용한다. 만약 해당 메소드를 다른 메소드에서 참조하면, 경고가 발생한다.

어노테이션을 선언할 때 사용하는 어노테이션을 무엇이라고 부르나요?
어노테이션을 선언할 때 사용하는 어노테이션을 메타 어노테이션(Meta annotation)이라고 부른다. 

4번 문제의 답에 있는 어노테이션들을 사용할 때 import 해야 하는 패키지는 무엇인가요? 
메타 어노테이션을 선언하기 위해서는 java.lang.annotation 패키지에 선언된 메타 어노테이션 관련 클래스들을 import해야만 한다.

@Target 어노테이션의 용도는 무엇인가요? 
@Target 어노테이션은 선언하는 어노테이션의 적용 범위를 정할 때 사용한다.

@Retention 어노테이션의 용도는 무엇인가요? 
@Retention 어노테이션은 어노테이션 정보가 언제까지 유효한지를 선언한다. 컴파일에서 실행시까지 어노테이션이 유효한 정도를 정할 수 있다.

@Inherited 어노테이션의 용도는 무엇인가요?
@Inherited 어노테이션은 모든 자식 클래스에서 부모 클래스의 어노테이션을 사용 가능하다는 것을 선언한다. 

어노테이션을 선언할 때에는 class 대신 어떤 예약어를 사용해야 하나요? 

어노테이션을 선언할 때에는 class라는 예약어 대신 @interface라는 어노테이션을 사용한다. 

 

 

그럼 이만.