728x90
📍 학습 목표
애노테이션의 탄생 배경과 종류를 알아보자!
애노테이션 탄생 배경
원래는 소스코드와 소스코드에 대한 문서가 개별적으로 존재했다. 그러면 소스코드를 변경할 때 마다 문서도 같이 변경을 해줘야한다. 그런 불편함 때문에 애노테이션을 통해서 소스코드와 문서를 하나의 파일로 관리하게 됐다. 애노테이션이 나오면서 소스코드와 문서에 대한 버전 불일치가 해결되었다. javadoc.exe를 통해서 소스 코드에 적혀있는 주석이나 애노테이션을 읽어서 문서를 만들 수 있다.
예전에는 설정 정보를 xml 파일로 관리했다. 이것의 단점은 xml 파일은 하나이기 때문에 협업시 하나의 파일을 공유해야 한다. 설정파일과 소스파일이 분리되어 있어서 서로 관리하기가 어렵다. 하지만 애노테이션을 통해 xml 파일을 대체할 수 있다. 그래서 소스코드 하나만 공유하면 된다.
애노테이션
- 모든 애노테이션의 조상은 Annotation 인터페이스다.
- 애노테이션 인터페이스를 보면 '/**' 로 시작하는 주석 안에 소스코드에 대한 설명들이 있고, 그 안에 '@'이 붙은 태그들이 존재한다. 미리 정의된 태그들을 이용해서 주석 안에 정보를 저장하고, javadoc.exe 프로그램이 이 정보를 읽어서 문서를 작성하는데 사용한다
- 애노테이션이란, 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것이다.
- 애노테이션은 자바 컴파일러에게 메시지를 전달하는 목적을 가지고 있다.
- 애노테이션은 java.lang.annotion 패키지에 포함되어 있다.
- 모든 애노테이션은 equals(), hashCode(), toString()과 같은 메서드를 호출할 수 있다.
📌 애노테이션 종류
🔍 @Override
- 메서드 앞에서만 붙일 수 있는 애노테이션이다.
- 조상의 메서드를 오버라이딩 하는 것이라는걸 컴파일러에게 알려주는 역할을 한다.
- 해당 애노테이션을 붙이면 컴파일러가 같은 이름의 메서드가 조상에 있는지 확인하고 없으면, 에러 메시지를 출력한다.
- 오버라이딩할 때 필수는 아니지만 실수 방지를 위해서 붙이도록 하자
🔍 @Deprecated
- 다른 것으로 대체되었으니 더 이상 사용하지 않을 것을 권한다는 의미다.
🔍 @FunctionalInterface
- 함수형 인터페이스(functional interface)를 선언할 때, 해당 애노테이션을 붙이면 컴파일러가 함수형 인터페이스를 올바르게 선언 했는지 확인하고. 잘못된 경우 에러를 발생시킨다.
- 참고) 함수형 인터페이스는 추상 메서드가 하나뿐이어야한다.
🔍 @SuppressWarnings
- 컴파일러가 보여준느 경고메시지를 나타나지 않게 억제해준다.
- 해당 애노테이션으로 억제할 수 있는 경고 메시지 종류는 많지 않다
- deprecation
- @Deprecated가 붙은 대상을 사용해서 발생하는 경고
- unchecked
- 제네릭으로 타입을 지정하지 않았을 때 발생하는 경고
- rawtypes
- 제네릭을 사용하지 않아서 발생하는 경고
- varargs
- 가변인자의 타입이 제네릭 타입일 때 발생하는 경고
- deprecation
- 해당 애노테이션의 경고의 억제범위를 최소화 하는것이 좋다. 안 그러면 나중에 추가된 코드에서 발생할 수 있는 경고까지 억제될 수 있기 때문에 바람직하지 않다.
💡 사용 방법
@SuppressWarnings("unchecked") // 제네릭과 관련된 경고 억제
ArrayList list = new ArrayList(); // 제네릭 타입 미지정
list.add(1); // 여기서 경고가 발생
@SuppressWarnings({"deprecation", "unchecked", "varargs"})
- 만약에 둘 이상의 경고를 동시에 억제하려면 배열처럼 괄호를 추가로 사용해야한다.
📌 마커 애노테이션
- 요소가 하나도 정의되지 않은 애노테이션을 마커 애노테이션이라고 한다.
📌 메타 애노테이션
- 메타 애노테이션은 애노테이션을 위한 애노테이션이다.
- 즉, 애노테이션에 붙이는 애노테이션으로 애노테이션을 정의할 때 애노테이션의 적용 대상(target)이나 유지기간(rentention)등을 지정하는데 사용된다.
🔍 @Target
- 애노테이션이 적용가능한 대상을 지정하는데 사용된다.
💡 @Target으로 지정할 수 있는 애노테이션 적용 대상의 종류
🔍 @Retention
- 애노테이션이 유지되는 기간을 지정하는데 사용된다.
🔍 @Documented
- 애노테이션의 정보가 javadoc으로 작성한 문서에 포함되도록 한다.
- 기본 애노테이션 중에 @Override, @SuppressWarnings를 제외하고는 모두 이 메타 애노테이션이 붙어있다.
🔍 @Inherited
- 애노테이션이 자손 클래스에 상속되도록 한다.
- @Inherited가 붙은 애노테이션을 조상 클래스에 붙이면 자손 클래스도 이 애노테이션이 붙은 것으로 인식된다.
- 애노테이션을 자손 클래스에 상속하고자 할 때, 해당 애노테이션을 붙인다.
📌 애노테이션 타입 정의하기
@interface 애노테이션이름 {
타입 요소이름A(); // 애노테이션의 요소 선언
int 요소이름B() defult 5; // 기본값을 5로 지정
...
}
- 애노테이션 내에 선언된 메서드를 애노테이션의 요소라고 한다.
- @Override는 애노테이션이지만 Override는 애토네이션의 타입이다.
- 애노테이션의 요소는 반환값이 있고 매개변수는 없는 추상메서드의 형태를 가지며 상속을 통해 구현하지 않아도 된다.
- 애노테이션을 적용할 때 요소들의 값을 빠짐없이 지정해주어야한다. 단, 요소의 순서는 상관없다.
- 애노테이션을 인터페이스처럼 상수는 정의할 수 있지만 디폴트 메서드는 정의할 수 없다.
- 애노테이션의 각 요소는 기본값을 가질 수 있다.
@interface TestInfo{
String value();
}
@TestInfo("passed") // @TestInfo(value = "passed") 와 같다.
- 애노테이션 요소가 하나만 가지고 있으면 애노테이션을 적용할 때, 요소의 이름을 생략하고 값만 적어도 된다.
📌 애노테이션 요소의 규칙
- 요소의 타입은 기본형, String, enum, 애노테이션, Class만 허용된다.
- 괄호() 안에 매개변수를 선언할 수 없다.
- 예외를 선언할 수 없다.
- 요소를 타입 매개변수로 정의할 수 없다. → 제네릭 불가능
@interface AnnoTest {
int id = 100; // ok. 상수 선언
// String major(int i, int j); / /에러 매개변수 선언 못함
// String minor() throws Exception; // 에러. 예외 선언 못함
// ArrayList<T> list(); // 에러, 요소의 타입에 타입 매개변수 사용 불가능
}
예제
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@TestInfo(
testeBy = "aaa",
testDate = @DateTime(yymmdd="220126", hhmmss = "235959"),
count = 5
)
public class Prac {
public static void main (String[] args) {
Class<Prac> cls = Prac.class;
TestInfo anno = (TestInfo)cls.getAnnotation(TestInfo.class);
System.out.println(anno);
System.out.println(anno.count());
System.out.println(anno.testeBy());
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface DateTime {
String yymmdd();
String hhmmss();
}
@Retention(RetentionPolicy.RUNTIME)
@interface TestInfo {
int count() default 1;
String testeBy();
String[] testTools() default "JUnit";
TestType testType() default TestType.FIRST;
DateTime testDate();
}
enum TestType {FIRST, FINAL}
@TestInfo(count=5, testType=FIRST, testTools={"JUnit"}, testeBy="aaa", testDate=@DateTime(yymmdd="220126", hhmmss="235959"))
5
aaa
- Prac.class는 클래스 객체를 의미하는 리터럴이다.
- 모든 클래스 파일은 클래스로더에 의해 메모리에 올라갈 때, 클래승 ㅔ대한 정보가 담긴 객체를 생성하는데 이 객체를 클래스 객체라고 한다.
- 이 객체를 참조할 때는 클래스이름.class 의 형식으로 사용한다.
- 클래스 객체는 해당 클래스에 대한 모든 정보를 가지고 있는데, 애노테이션의 정보도 포함되어 있다.
728x90
'[자바] > 자바' 카테고리의 다른 글
[Java] Optional<T> 클래스 (0) | 2022.02.07 |
---|---|
[Java] 메서드 참조 (Method References) (0) | 2022.02.04 |
[Java] 함수형 인터페이스 (0) | 2022.02.03 |
[Java] 내부 클래스, 네스티드(Nested) 클래스, 익명 클래스 (0) | 2022.01.27 |
[Java] 열거형 (enum) (0) | 2022.01.26 |