본문 바로가기

JAVA

[JAVA] 어노테이션 (Annotation)


어노테이션이란?


어노테이션(Annotation)은 사전적으로는 "주석"이라는 의미를 가지고 있습니다.

자바에서는 @를 이용하여 주석처럼 달아 특수한 의미를 부여해줍니다.

어노테이션은 소스 코드가 컴파일되거나 실행될 때 컴파일러 및 다른 프로그램에게 필요한 정보를 전달해 주는 문법 요소입니다.

 

어노테이션의 종류


JDK에서 기본적으로 제공하는 어노테이션은 아래의 두 가지로 분류됩니다.

  1. 표준 어노테이션: 자바에서 기본적으로 제공하는 어노테이션
  2. 메타 어노테이션: 다른 어노테이션에서도 사용되는 어노테이션을 말하며, custom-annotation을 생성할 때 주로 사용

 

표준 어노테이션


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

표준 어노테이션을 여러 가지가 있지만, 그중에서도

  • @Override
  • @Deprecated
  • @SuppressWarning
  • @FunctionaIInterface

위의 네 어노테이션이 가장 많이 사용되며, 이를 자세히 알아보도록 하겠습니다.

 

@Override


@Override 어노테이션은 메서드 앞에 오는 어노테이션입니다.

상위클래스의 메서드를 오버라이딩한다는 것을 컴파일러에게 알리는 역할을 합니다.

 

그렇다면 @Override 어노테이션을 사용하는 이유는 무엇일까요?

아래의 코드 예제를 보도록 하겠습니다

class SuperClass {
	void eat() {...}
}

class SubClass extends UpperClass {
	void eta(int a) {...}
    // 프로그래머의 오타로 eat을 eta로 입력
}

위의 코드 예제를 보면, 상위 클래스의 메서드를 오버라이딩하려던 중 오타가 발생한 모습입니다.

이러한 경우, 위 예시처럼 @Override를 붙이지 않으면 컴파일러는 eta()라는 새로운 메서드를 정의하는 것으로 간주하여, 에러를 발생시키지 않습니다.

이후 런타임 에러가 발생한다면 어디에서 에러가 발생했는지 에러의 원인을 찾아내기 어려워집니다.

 

그러나, @Override를 사용하여 eat()이 오버라이딩 메서드라는 것을 컴파일러가 인지하고, 상위 클래스에 eat()이 존재하는지 확인하기 때문에, 이러한 상황을 방지할 수 있습니다.

 

즉, @Override 메서드를 이용하여 프로그래머의 실수를 방지할 수 있습니다.

아래의 예제 코드는 @Override를 올바르게 사용하는 모습입니다.

class SuperClass {
	public void eat() {
    	...
    }
}

class SubClass extends SuperClass{
	@Override
    	public void eat(){
    	...
    }
}

 

@Deprecated


@Deprecate 어노테이션은 새로운 버전의 JDK가 등장하여 더 이상 사용하지 않는 필드나 메서드가 있을 경우 사용합니다.

즉, @Deprecated 어노테이션은 필드나 메서드가 새로운 것으로 업데이트되었을 때, 기존의 것을 사용하지 않도록 합니다.

 

따라서 해당 메서드가 하위 버전의 호환성 문제로 삭제하기 곤란하여 남겨두어야만 할 때 @Deprecated 어노테이션을 이용합니다.

아래의 예제 코드를 보도록 하겠습니다

class OldClass {
	@Deprecated
    	private int oldField;
    
    	@Deprecated
    	int getOldField() {
    	return oldField;
    }
}

이처럼 @Deprecated 어노테이션이 있는 메서드를 호출할 때 경고 메시지를 확인할 수 있습니다.

 

@SuppressWarning


@SuppressWarning 어노테이션은 컴파일 경고 메시지가 나타나지 않도록 합니다.

어노테이션 설명
@SuppressWarings("all") 모든 경고를 억제
@SuppressWarings("deprecation") Deprecated 메서드를 사용한 경우에 발생하는 경고를 억제
@SuppressWarings("fallthrough") switch문에서 break 구문이 없을 때 발생하는 경고를 억제
@SuppressWarings("finally") finally와 관련된 경고를 억제
@SuppressWarings("null") null과 관련된 경고를 억제
@SuppressWarings("unchecked") 검증되지 않은 연산자와 관련된 경고를 억제
@SuppressWarings("unused") 사용하지 않는 코드와 관련된 경고를 억제

아래의 예제는 여러 개의 경고를 한 번에 묵인하게 할 수 있습니다

@SuppressWarnings({"deprecation","unchecked","null"})

 

@FunctionaIInterface


@FunctionalInterface 애너테이션은 함수형 인터페이스를 선언할 때, 컴파일러가 함수형 인터페이스의 선언이 바르게 선언되었는지 확인하도록 합니다.

아래의 예제 코드는 @FunctionalInteface를 사용한 코드 예제입니다.

@FunctionalInterface
public interface ExampleInterface {
	pulbic abstract void example();
}

 

함수형 인터페이스에 관한 내용은 람다(Lambda)에서 확인할 수 있습니다

람다에 대한 글은 아래를 확인 부탁드리겠습니다.

 

메타 어노테이션


메타 어노테이션(meta annotation)은 어노테이션을 정의하는 데 사용되는 어노테이션이라 설명하였습니다.

 

우선, @Override가 어떻게 정의되어 있는지 확인해 보도록 하겠습니다

@Override의 소스 코드를 보면, 어노테이션을 정의할 때는 @interface 키워드를 사용하여 정의한 것을 확인할 수 있습니다.

 

 

또한, 어노테이션 정의부 상단에 @Target, @Retention 애너테이션이 있는 것을 확인할 수 있습니다.

이들은 @Override의 적용 대상과 유지기간을 지정해 주는 역할을 합니다.

 

위의 @Target과, @Retention은 메타 어노테이션의 대표적인 어노테이션입니다.

위의 어노테이션과 함께 대표적인 어노테이션은 아래와 같습니다.

  • @Target
  • @Documented
  • @Retention
  • @Inherited
  • @Repeatable

위의 어노테이션을 자세히 알아보도록 하겠습니다.

@Target

@Target 어노테이션은 적용할 "대상"을 지정하는 데 사용합니다.

어노테이션 설명
ElementType.TYPE 클래스, 인터페이스, enum
ElementType.FIELD 필드
ElementType.METHOD 메서드
ElementType.PARAMETER 파라미터
ElementType.CONSTRUCTOR 생성자
ElementType.LOCAL_VARIABLE 지역 변수
ElementType.ANNOTATION_TYPE 어노테이션
ElementType.PACKAGE 패키지
ElementType.TYPE 클래스, 인터페이스 enum
ElementType.TYPE_PARAMETER 타입 파라미터
ElementType.TYPE_USE 타입
ElementType.MODULE 모듈
  • @Target()의 value로 ElementType을 지정하지 않으면 오류가 납니다.

 


@Documented

@Documented 어노테이션은 javadoc으로 작성한 문서에 포함되도록 하는 어노테이션 설정입니다.

@Documented
@Target(ElementType.Type)
public @interface CustomAnnotation { }

@Inherited

@Inherited 어노테이션은 하위 클래스가 어노테이션을 상속받도록 합니다.

@Inherited 어노테이션을 상위 클래스에 붙이면, 하위 클래스도 상위 클래스의 어노테이션들이 동일하게 적용됩니다.

@Inherited //@SuperAnnotation이 하위 클래스까지 적용
@interface SuperAnnotation{ }

@SuperAnnotation
class Super { }

class Sub extends Super{ } // Sub class에 어노테이션이 붙은 것으로 인식

위의; 코드 예제를 보면, Super 클래스로부터 확장된 Sub 클래스는 상위 클래스와 동일하게 @SuperAnnotation에 정의된 내용들을 적용받게 됩니다.

 


@Retention

@Retention 어노테이션은 어노테이션의 지속 시간을 결정하는 데 사용합니다. 어노테이션과 관련한 유지 정책(retention policy)의 종류는 다음 3가지가 있습니다

  1. SOURCE : 소스 파일에 존재, 클래스파일에는 존재하지 않음
  2. CLASS : 클래스 파일에 존재, 실행 시에 사용불가, 기본 값
  3. RUNTIME: 클래스 파일에 존재, 실행시에 사용 가능

@Repeatable

마지막으로, @Repeatable 어노테이션은 어노테이션을 여러 번 붙일 수 있도록 허용한다는 의미를 가지고 있습니다.

예제에서, 사용자 타입의 어노테이션 Work를 정의하고, @Repeatable 어노테이션을 사용하여 이것을 여러 번 사용할 수 있도록 하였습니다

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

@Work("code update")
@Work("method overriding")
class Main {
	...
}