애너테이션이란?
에너테이션은 소스 코드가 컴파일 되거나 실행될 때 컴파일러 및 다른 프로그램에게 필요한 정보를 전달해주는 문법 요소이다. 어떻게 생겼는지 직접 확인해보자.
먼저 아래와 같이 인터페이스를 정의해보자.
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();
}
'공부 > 전자컴퓨터공학' 카테고리의 다른 글
Java 스트림(Stream) 이란? 자바 기초 배우기 (0) | 2024.05.30 |
---|---|
Java 람다식(Lambda Expression)이란? 자바 기초 배우기 (0) | 2024.05.30 |
Java 컬렉션 프레임워크란? 자바 기초 배우기 (0) | 2024.05.30 |
Java 예외처리(Exception Handling)란? 자바 기초 배우기 (1) | 2024.05.28 |
Java 제네릭(Generic) 이란? 자바 기초 배우기 (0) | 2024.05.28 |