공부/전자컴퓨터공학

Java 애너테이션(Annotation) 이란? 자바 기초 배우기

AhJustC 2024. 5. 30. 01:50
반응형
애너테이션이란?

에너테이션은 소스 코드가 컴파일 되거나 실행될 때 컴파일러 및 다른 프로그램에게 필요한 정보를 전달해주는 문법 요소이다. 어떻게 생겼는지 직접 확인해보자.

 

먼저 아래와 같이 인터페이스를 정의해보자.

public interface ExampleInterface {
    void example();
}

 

그 다음 아래와 같이 클래스를 정의하고 ExampleInterface를 구현하자.

public class ExampleClass implements ExampleInterface {

}

 

alt + insert 를 입력 후 Implement Methods를 클릭하여 ExampleInterface의 추상 메서드를 구현하자.

OK를 눌러 입력을 완료하면 구현해야 하는 메서드가 자동으로 정의된다.

public class ExampleClass implements ExampleInterface {
    @Override
    public void example() {

    }
}

여기에서 보이는 @Override가 바로 애너테이션이다. 애너테이션은 @로 시작하며 클래스, 인터페이스, 필드, 메서드 등에 붙여서 사용할 수 있다. 참고로 위의 @Override는 example()이 추상 메서드를 구현하거나, 상위 클래스의 메서드를 오버라이딩한 메서드라는 것을 컴파일러에게 알려주는 역할을 한다. 

이처럼 애너테이션은 컴파일러 또는 다른 프로그램에 필요한 정보를 제공해주는 역할을 한다.

 

@Override

@Override는 메서드 앞에만 붙일 수 있는 애너테이션으로, 선언한 메서드가 상위 클래스의 메서드를 오버라이딩하거나 추상 메서드를 구현하는 메서드라는 것을 컴파일러에게 알려주는 역할을 수행한다. 예를들어 아래와 같이 SuperClass의 example()을 SubClass에서 오버라이딩 할 때에 @Override를 붙여주면 컴파일러는 SubClass의 example()이 상위 클래스의 메서드를 오버라이딩한 것으로 간주한다.

class SuperClass {
    public void example() {
        System.out.println("example() of SuperClass");
    }
}

class SubClass extends SuperClass {

    @Override
    public void example() {
        System.out.println("example() of SubClass");
    }
}

컴파일 과정에서 컴파일러가 @Override를 발견하면 @Override가 붙은 메서드와 같은 이름을 가진 메서드가 상위 클래스나 인터페이스에 존재하는지 검사한다. 즉 SuperClass에 example()이 존재하는지 검사한다.

만약 상위클래스나 인터페이스에 @verride가 붙어있는 메서드명과같은 이름의 메서드를 찾을 수 없다면 컴파일러가 컴파일 에러를 발생시킨다.

반응형

상위 클래스에 오버라이딩같은 같은 이름의 메서드가 존재하는지 확인하는 이유는 종종 코드를 작성하다보면 어떤 메서드를 오버라이딩 하거나 구현할 때 개발자의 실수로 메서드의 이름이 잘못 작성되는 경우가 발생하기 때문이다.

class SuperClass {
    public void example() {
        System.out.println("example() of SuperClass");
    }
}

class SubClass extends SuperClass {

    public void exapmle() { // 메서드 이름에 오타가 있습니다.
        System.out.println("example() of SubClass");
    }
}

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

 

@Deprecated

기존에 사용하던 기술이 다른 기술로 대체되어 기존 기술을 적용한 코드를 더 이상 사용하지 않도록 유도하는 경우에 사용한다.

아래 예시를 보면 OldClass의 OldField와 getOldField()에 @Deprecated가 붙어있다.

class OldClass {
	@Deprecated
	private int oldField;

	@Deprecated
	int getOldField() { return oldField; }
}

이때, 다른 클래스에서 OldClass를 인스턴스화하여 getOldField()를 호출하면 아래와 같이 취소선이 뜨면서 경고를 출력해준다.

또한 해당 코드를 직접 컴파일 해보면 아래와 같은 경고메세지가 출력된다.

이처럼 @Deprecated는 애너테이션이 붙은 대상이 새로운 것으로 대체되었으니 기존의 것을 사용하지 않도록 유도하는 기능을 한다. 즉 기존의 코드를 다른 코드와의 호환성 문제로 삭제하기 곤란해 남겨두어야만 하지만 더 이상 사용하는 것을 권장하지 않을 때 사용한다.

 

SuppressWarnings

@SuppressWarnings 에너테이션은 컴파일 경고 메시지가 나타나지 않도록 한다. 때에 따라서 경고가 발생할 것이 충분히 예상됨에도 묵인해야 할 때 주로 사용한다. 

아래와 같이 @SuppressWarnings 뒤에 괄호를 붙이고 그 안에 억제하고자 하는 경고메시지를 지정해줄 수 있다. 

더 나아가 아래와 같이 중괄호에 여러개의 경고 유형을 나열함으로써 여러 개의 경고를 한번에 묵인하게 할 수 있다.

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

 

@FunctionalInterface

@FunctionalInterface 애너테이션은 함수형 인터페이스를 선언할 때 컴파일러가 함수형 인터페이스의 선언이 바르게 되었는지 확인하도록 하며 바르게 선언되지 않은 경우 에러를 발생시킨다.

@FunctionalInterface
public interface ExampleInterface {
	public abstract void example(); // 단 하나의 추상 메서드
}

 

@Target

@Target 애너테이션은 애너테이션을 적용할 대상을 지정하는데 사용된다. 다음 표의 내용이 @Target 애너테이션을 사용하여 지정할 수 있는 대상의 타입이며 모두 java.lang.annotation.ElementType 이라는 열거형에 정의되어 있다.

대상 타입 적용 범위
ANNOTATION_TYPE 애너테이션
CONSTRUCTOR 생성자
FIELD 필드(멤버변수, 열거형 상수)
LOCAL_VARIABLE 지역변수
METHOD 메서드
PACKAGE 패키지
PARAMETER 매개변수
TYPE 타입(클래스, 인터페이스, 열거형)
TYPE_PARAMETER 타입 매개변수
TYPE_USE 타입이 사용되는 모든 대상

 

예시를 통해 좀 더 알아보자.

import static java.lang.annotation.ElementType.*;
//import문을 이용하여 ElementType.TYPE 대신 TYPE과 같이 간단히 작성할 수 있습니다.

@Target({FIELD, TYPE, TYPE_USE})	// 적용대상이 FIELD, TYPE
public @interface CustomAnnotation { }	// CustomAnnotation을 정의

@CustomAnnotation	// 적용대상이 TYPE인 경우
class Main {

		@CustomAnnotation	// 적용대상이 FIELD인 경우
    int i;
}

 

@Target({FIELD, TYPE, TYPE_USE})을 사용하여 각각 필드, 타입, 그리고 타입이 사용되는 모든 변수에 애너테이션이 적용되도록 한 것을 확인할 수 있다.

 

@Documented

애너테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 하는 애너테이션 설정이다.

자바에서 제공하는 표준 애너테이션과 메타 애너ㅓ테이션 중 @Override와 @SuppressWarnings를 제외하고는 모두 @Documented가 적용되어 있다.

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

 

@Inherited

하위 클래스가 애너테이션을 상속받도록 한다.

Super 상위 클래스로부터 확장된 Sub 하위 클래스는 상위 클래스와 동일하게 @SuperAnnotation에 정의된 내용들을 적용받게 된다.

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

@SuperAnnotation
class Super { }

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

 

@Retention

애너테이션의 지속시간을 결정하는데 사용한다. 애너테이션과 관련한 유지 정책(retention policy)의 종류에는 세 가지가 있다.

유지정책 설명
SOURCE 소스 파일에 존재, 클래스파일에는 존재하지 않음
CLASS 클래스 파일에 존재, 실행 시에 사용 불가, 기본값
RUNTIME 클래스 파일에 존재, 실행 시에 사용가능

 

각각의 유지 정책은 언제까지 애너테이션이 유지될지를 결정한다.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
//오버라이딩이 제대로 되었는지 컴파일러가 확인하는 용도
//클래스 파일에 남길 필요 없이 컴파일 시에만 확인하고 사라짐
public @interface Override(){ }

 

@Repeatable

애너테이션을 여러 번 붙일 수 있도록 허용하는 애너테이션이다. 아래 예제에서 사용자 타입의 애너테이션 Work를 정의하고, @Repeatable 애너테이션을 사용하여 이것을 여러번 사용할 수 있도록 했다.

@Repeatable(Works.class) // Work 애너테이션을 여러 번 반복해서 쓸 수 있게 한다.
@interface Work{
    String value();
}

아래와 같이 Work 애너테이션을 하나의 대상에 여러번 적용하는 것이 가능해졌다.

@Work("코드 업데이트")
@Work("메서드 오버라이딩")
class Main{
	... 생략 ...
}

@Repeatable 애너테이션은 일반적인 애너테이션과 달리 같은 이름의 애너테이션이 여러번 적용될 수 있기 때문에 이 애너테이션을 하나로 묶어주는 애너테이션도 별도로 작성해야 한다.

@interface Works {  // 여러 개의 Work애너테이션을 담을 컨테이너 애너테이션 Works
    Work[] value();
}

@Repeatable(Works.class) // 컨테이너 애너테이션 지정
@interface Work {
	String value();
}
반응형