애너테이션@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarings { String[] value(); }
: 자바 개발자들은 소스코드에 대한 문서를 따로 만들기 보다 소스코드의 주석'/** ~ */' 에 소스코드에 대한 정보를 저장하고 그 주석으로 부터 html문서를 생성해내는 프로그램(javadoc.exe)을 만들어서 사용했다.
이와 같은 기능을 응용하여, 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨것이 바로 애너테이션이다.
애너테이션은 주석처럼 프로그래밍 언어에 영향을 미치지 않으면서도 다른 프로그램에게 유용한 정보를 제공할 수 있는 장점이 있다.
* 애너테이션의 종류
1. 표준 애너테이션 : JDK에서 기본적으로 제공하는 애너테이션, 주로 컴파일러에게 유용한 정보를 제공한다.
2.메타 애너테이션 : 새로운 애너테이션을 정의할 때 사용한다.
* 표준 애너테이션
@Override
: 메서드 앞에서만 붙일 수 있는 애너테이션으로, 조상의 메서드를 오버라이딩하는 것이라는 걸 컴파일러에게 알려주는 역할을 한다.
아래 코드와 같이 메서드 앞에 '@Override'라고 애너테이션을 붙이면, 컴파일러가 같은 이름의 메서드가 조상에 있는지 확인하고 없으면, 에러메시지를 출력한다.
class Child extends Parent {
@Override
void parentmenthod() {}
}
/* 오류 케이스 */
class Parent {
void AAA(){}
}
class Child extends Parent {
@Override
void aaa(){} // 조상 메서드의 이름을 잘못적어서 오류 발생.
}
@Deprecated
: 더 이상 사용되지 않는 필드나 메서드에 붙인다. 이 애너테이션이 붙은 대상은 다른 것으로 대체 되었으니 더 이상 사용하지 않을 것을 권한다는 의미이다.
@Deprecated가 붙은 대상을 사용하면, 컴파일 시 아래와 같은 메시지가 출력된다.
Note : ClassFile.java uses or overrides a deprecated API.
Note : Recompile with -Xlint:deprecation for details.
해당 소스파일이 'deprecated'된 대상을 사용하고 있으며, '-Xlint:deprecation' 옵션을 붙여서 다시 컴파일 하면 자세한 내용을 알 수 있다는 뜻이다.
이런 메시지가 나타날뿐 컴파일 실행은 문제 없다.
@Functionallnterface
: '함수형 인터페이스'를 선언할 때, 이 애너테이션을 붙이면 컴파일러가 '함수형 인터페이스'를 올바르게 선언했는지 확인하고 잘못된 경우 에러를 발생시킨다. 필수는 아니지만 실수방지를 위해 '함수형 인터페이스'를 선언할 때 꼭 붙이는걸 권장한다.
@FunctionalInterface
public interface Runnable {
public abstract void run(); // 추상메서드
}
@SuppressWarnings
: 컴파일러가 보여주는 경고메시지가 나타나지 않게 억제해준다.
억제할 수 있는 경고 메시지의 종류는 JDK의 버전이 올라가면서 계속 추가되겠지만, 주로 사용되는 것은
"deprecation","unchecked","rawtypes","varargs" 가 있다.
억제하려는 경고 메시지를 애너테이션의 뒤에 괄호()안에 문자열로 지정하면 된다.
deprecation | '@Deprecated'가 붙은 대상을 사용해서 발생하는 경고 억제. |
unchecked | 지네릭스로 타입을 지정하지 않았을 때 발생하는 경고 억제. |
rawtypes | 지네릭스를 사용하지 않아서 발생하는 경고 억제. |
varargs | 가변인자의 타입이 지네릭 타입일때 발생하는 경고를 억제. |
/* 예시 */
@SuppressWarnings("unchecked")
ArrayList list = new ArrayList(); // 지네릭 타입을 지정하지 않았음.
list.add(obj); // 여기서 경고 발생
/* 둘 이상의 경고를 동시에 억제하려면 괄호를 사용한다. */
@SuppressWarnings({"deprecation","unchecked","varargs"})
/* 경고 메시지의 종류를 알아내는 법 */
/* -Xlint옵션으로 컴파일해서 나타나는 경고의 내용중에서 대괄호[]안에 있는 것을 확인하면 된다. */
@SafeVarargs
: 컴파일 이후에 제거되는 타입을 non-reifiable타입, 제거되지 않는 타입을 reifiable타입이라고 한다.
메서드에 선언된 가변인자의 값이 non-reifiable타입인 경우, 해당 메서드를 선언하는 부분과 호출하는 부분에서 "unchecked" 경고가 발생하는데 이 애너테이션을 붙이면 해당 경고를 억제할 수 있다.
static이나 final이 붙은 메서드와 생성자, 즉 오버라이드가 될 수 없는 메서드에만 붙일 수 있다.
/* 예시 */
import java.util.Arrays;
class MyArrayList<T> {
T[] arr;
@SafeVarargs
@SuppressWarnings("varargs") //@SafeVarargs로 unchecked 경고는 억제할 수 있지만 'varargs'경고는 억제할 수 없기 때문에
MyArrayList(T...arr){ // 습관적으로 @SafeVarargs와 @SuppressWarnings("varargs")를 같이 붙인다.
this.arr = arr;
}
@SafeVarargs
// @SuppressWarnings("unchecked")
public static <T> MyArrayList<T> asList(T...a){
return new MyArrayList<>(a);
}
public String toString() {
return Arrays.toString(arr);
}
}
class AnnontationEx {
// @SuppressWarnings("unchecked")
public static void main(String args[]){
MyArrayList<String> list = MyArrayList.asList("1","2","3");
}
}
* 메타 애너테이션
@Target
: 애너테이션이 적용가능한 대상을 지정하는데 사용된다.
여러개의 값을 지정할 때는 괄호{}를 사용한다.
/* 예시 */
@Target({TYPE, FIELD, TYPE_USE})
public @interface MyAnnotation {} // @MyAnnotation 정의
@MyAnnotation // 적용대상이 type인 경우, 타입을 선언할 때 애너테이션을 붙일 수 있다.
class MyClass {
@MyAnnotation // 적용대상이 field인 경우, 해당 타입의 변수를 선언할 때 붙일 수 있다.(기본형)
int i;
@MyAnnotation // 적용대상이 type_use인 경우, 해당 타입의 변수를 선언할 때 붙일 수 있다.(참조형)
MyClass mc;
}
* @Target으로 지정할 수 있는 애너테이션 적용대상의 종류
대상 타입 | 의미 |
ANINOTATION_TYPE | 애너테이션 |
CONSTRUCTOR | 생성자 |
FIELD | 필드(멤버변수, enum 상수) |
LOCAL_VARIABLE | 지역변수 |
METHOD | 메서드 |
PACKAGE | 패키지 |
PARAMETER | 매개변수 |
TYPE | 타입(클래스, 인터페이스, enum) |
TYPE_PARAMETER | 타입 매개변수(JDK1.8) |
TYPE_USE | 타입이 사용되는 모든 곳(JDK1.8) |
@Retention
: 에너테이션이 유지되는 기간을 지정하는데 사용된다.
* 애너테이션의 유지 정책 종류
유지 정책 | 의미 |
SOURCE | 소스 파일에만 존재. 클래스파일에는 존재하지 않음, 컴파일러가 사용하는 애너테이션 유지정책. |
CLASS | 클래스 파일에 존재. 클래스 파일이 JVM에 로딩될 때에는 애너테이션의 정보가 무시되어 실행 시에 애너테이션에 대한 정보를 얻을 수 없음. 그래서 기본값임에도 잘 사용되지 않는다. |
RUNTIME | 클래스 파일에 존재. 실행시에 사용가능 |
@Documented
: 애너테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다.
기본 에너테이션 중에 @Override와 @SuppressWarnings를 제외하고는 모두 이 애너테이션이 붙어져있다.
@Inherited
: 애너테이션이 자손 클래스에 상송되도록 한다.
이 애너테이션을 조상클래스에 붙이면, 자손 클래스도 이 애너테이션이 붙은 것과 같이 인식된다.
/* 예시 */
@Inherited // @SupperAnno 자손까지 영향 미치게
@interface SupperAnno {}
@SupperAnno
class Parant {}
class Child extends Parant {} // Child 클래스에도 @SupperAnno 애너테이션이 붙은 것으로 인식
@Repeatable
: 보통은 하나의 대상에 한 종류에 애너테이션을 붙이는데, '@Repeatable'이 붙은 애너테이션은 여러번 붙일 수 있다.
@interface ToDos { // 여러 개 ToDo애너테이션을 담을 컨테이너 애너테이션 ToDos
ToDo[] value(); // ToDo애너테이션 배열타입의 요소를 선언. 이름이 반드시 value이어야 함.
}
@Repeatable(ToDos.class) // ToDo애너테이션을 여러 번 반복해서 쓸 수 있게 한다.
@interface ToDo{
String value();
}
@ToDo("delete test codes.")
@ToDo("override inherited methods") // 다중으로 사용 가능
class MyClass {
...
}
@Native
: 네이티브 메서드에 의해 참조되는 '상수 필드'에 붙이는 애너테이션이다.
* 네이티브 메서드는 JVM이 설치된 OS의 메서드를 말한다.
자바에서는 메서드의 선언부만 정의하고 구현은 하지않았다. 그래서 네이티브 메서드와 OS의 메서드를 연결해주는 작업이 필요하다.
이 역할은 JNI(Java Native Interface)가 한다.
@Native public static final long MIN_VALUE = 0x8000000000000000L;
* 애너테이션 정의 방법
@interface 애너테이션이름 {
타입 요소이름(); // 애너테이션의 요소를 선언한다.
...
}
1. 애너테이션 내에 선언된 메서드를 '애너테이션의 요소(element)'라고 한다.
2. 애너테이션의 요소는 반환값이 있고 매개변수는 없는 추상 메서드의 형태를 가지며, 상속을 통해 구현하지않아도 된다.
3. 요소들의 값은 빠짐없이 지정해주어야 한다. 순서는 상관없다.
4. 요소 타입이 배열인 경우, 괄호{}를 사용해서 여러 개의 값을 지정할 수 있다.
@TestInfo (
count = 3, testedBy = "Kim",
testTools = {"JUnit","AutoTester"}, // 값이 여러개인 경우, 하나일때는 생략가능. 없을때에는 빈괄호{}가 반드시 필요. 기본값도 배열로 지정가능.
testType = TestType.FIRST,
testDate = @DateTime(yyyymmdd = "160101", hhmmss = "235959")
)
5. 각 요소들은 기본값을 가질 수 있고, 기본값이 있는 요소는 애너테이션을 적용할 때 지정하지 않으면 기본값이 사용된다.
@interface TestInfo {
int count() default 1; // 기본값을 1로 지정
}
@TestInfo // @TestInfo(count = 1)과 동일
public class NewClass { ... }
6. 애너테이션 요소가 한개뿐이고 이름이 value인 경우, 애너테이션을 적용할 때 요소의 이름을 생략하고 값만 적어도 된다.
요소의 타입이 배열일 때도 요소의 이르이 value이면 생략가능하다.
@interface TestInfo {
String value();
}
@TestInfo ("passed") // @TestInfo(value="passed")와 동일
class newClass{ ... }
마커 애너테이션
: 값을 지정할 필요가 없는 경우, 애너테이션의 요소를 하나도 지정하지 않을 수 있다.
이렇게 요소가 하나도 없는 애너테이션을 마커 애너테이션이라고 한다.
* 애너테이션의 규칙 - 애너테이션의 요소를 선언할 때, 반드시 지켜야하는 규칙.
1. 요소의 타입은 기본형, String, enum, 애너테이션, Class만 허용된다.
2. ()괄호 안에 매개변수를 선언할 수 없다.
3. 예외를 선언할 수 없다.
4. 요소를 타입 매개변수로 정의할 수 없다. ex) ArrayList<T> list(); 불가
* 참고 : 클래스의 객체에서 getAnnotation()이라는 메서드에 얻고 싶은 에너테이션을 지정하고 호출하거나 getAnnotations() 메서드를 호출하면 클래스에 지정된 애너테이션 정보를 얻을 수 있다.
728x90
반응형
'개발 공부 > Java & Spring' 카테고리의 다른 글
20. volatile (0) | 2023.03.09 |
---|---|
19. 쓰레드의 동기화 (0) | 2023.03.09 |
17. 열거형(enums) (0) | 2023.02.12 |
16. 해싱과 HashMap (0) | 2023.01.18 |
15. 이진 검색 트리와 TreeSet (0) | 2023.01.17 |