728x90
애너테이션
- 주석처럼 프로그래밍 언어에 영향을 미치지 않으며, 유용한 정보를 제공
@Test //이 메소드가 테스트 대상임을 테스트 프로그램에게 알림. JUnit. 단위 테스트 프로그램
public void method(){
...
}
표준 애너테이션
- 자바에서 제공하는 애너테이션
애너테이션 | 설명 |
@Override | 컴파일러에게 오버라이딩하는 메소드라는 것을 알림 |
@Deprecated | 앞으로 사용하지 않을 것을 권장하는 대상에 붙임 |
@SuppressWarnings | 컴파일러의 특정 경고메시지가 나타나지 않게 해줌 |
@SafeVarargs | 제네릭 타입의 가변인자에 사용 |
@FunctionalInterface | 함수형 인터페이스라는 것을 알림 |
@Native | native메소드에서 참조되는 상수 앞에 붙임 |
@Target | 애너테이션이 적용가능한 대상을 지정하는데 사용 |
@Documented | 애너테이션 정보가 javadoc으로 작성된 문서에 포함되게 함 |
@Inherited | 애너테이션이 자손 클래스에 상속되도록 함 |
@Retention | 애너테이션이 유지되는 범위를 지정하는데 사용 |
@Repeatable | 애너테이션을 반복해서 적용할 수 있게 함 |
- @Override (javac.exe)
오버라이딩을 올바르게 했는지 컴퍼일러가 체크하게 함
오버라이딩 할 때 메소드 이름을 잘 못 적는 실수를 하는 경우가 있음
class Parent{
void parentMethod() {}
}
class Child extends Parent{
@Override
// void parentmethod() {} //조상 메소드의 이름 오타
void parentMethod() {}
}
- @Deprecated
앞으로 사용하지 않을 것을 권장하는 필드나 메소드에 붙임
예 Date 클래스의 getDate()
@Deprecated가 붙은 대상이 사용된 코드를 컴파일하면 메시지가 나타남. 에러는 아님
//Date클래스의 getDate()
@Deprecated
public int getDate(){
return normalize().getDayOfMonth();
}
- @FunctionalInterface
함수형 인터페이스에 붙이면, 컴파일러가 올바르게 작성했는지 체크
함수형 인터페이스에는 하나의 추상메소드만 가져야 한다는 제약이 있음
※인터페이스 → 여러개의 추상메소드를 가질 수 있음
interface Testable{
void test();
void check();
}
//위의 Testable인터페이스에 @FunctionalInterface를 붙이면 에러 발생 → 하나의 추상 메소드만 가질 수 있기 때문에 test(), check() 중 하나를 제거해야함
0@FunctionalInterface
public interface Runnable{
void test();//한개의 추상 메소드.
// void check(); //에러. @FunctionalInterface가 붙은 인터페이스는 하나의 추상메소드만 가질 수 있음
}
- @SuppressWarnings
컴퍼일러의 경고메시지가 나타나지 않게 억제함
괄호() 안에 억제하고자하는 경고의 종류를 문자열로 지정
둘 이상의 경고를 억제하려면 @SuppressWarnings({"deprecation", "unchecked"}) {}안에 여러개 넣어줌
-Xlint옵션으로 컴파일하면 경고메시지를 확인할 수 있음. 괄호 []안이 경고의 종류
@SuppressWarnings("unchecked") //제네릭 관련된 경고를 억제
ArrayList list = new ArrayList(); //제네릭 타입을 지정하지 않음
list.add(obj); //여기서 경고발생
public class Study11 {
@SuppressWarnings("deprecation")
public static void main(String[] args) {
Child child = new Child();
child.parentMethod(); //deprecated된 메소드 사용
}
메타 에너테이션
- 애너테이션을 위한 애너테이션
- java.lang.annotation 패키지에 포함
- @Target, @Documented, @Inherited, @Retendtion, @Repeatable
- @Target
애너테이션을 정의할 때, 적용대상 지정에 사용
====================================
대상 타입 : 의미
ANNOTATION_TYPE : 애너테이션
CONSTRUCTOR : 생성자
FIELD : 필드(멤버변수, enum 상수)
LOCAL_VARIALBE : 지역변수
METHOD : 메소드
PACKAGE : 패키지
PARAMETER : 매개변수
TYPE : 타입(클래스, 인터페이스, enum)
TYPE_PARAMETER : 타입 매개변수
TYPE_USE : 타입이 사용되는 모든 곳
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.TYPE_USE}) //적용대상이 FIELD, TYPE, TYPE_USE
public @interface MyAnnotation{} //MyAnnotation을 정의
@MyAnnotation //적용 대상이 TYPE인 경우
class MyClass{
@MyAnnotation //적용대상이 FIELD인 경우
int i ;
@MyAnnotation //적용대상이 TYPE_USE인 경우
MyClass me;
}
- @Retention
애너테이션이 유지(retention)되는 기간을 지정하는 데 사용
====================================
유지정책 : 의미
SOURCE : 소스파일에만 존재. 클래스파일에는 존재하지 않음
CLASS : 클래스 파일에 존재. 실행시에 사용불가. 기본값
RUNTIME : 클래스 파일에 존재. 실행시에 사용가능
====================================
컴파일러에 의해 사용되는 애너테이션의 유지 정책은 SOURCE
실행시에 사용 가능한 애너테이션의 정책은 RUNTIME - @Documented
javac로 작성한 문서에 포함시키고자 할 때 붙임
@Documented
public @interface FunctionalInterface{}
- @Inherited
애너테이션을 자손 클래스에 상속하고자 할 때 붙임
@Inherited //@SuperAnoo가 자손까지 영향 미치게
@interface SuperAnno{}
@SuperAnno
class P{}
class C extends P{} //C에 애너테이션이 붙은 것으로 인식
- @Repeatable
반복해서 붙일 수 있는 애너테이션을 정의할 때 사용
@Repeatable이 붙은 애너테이션은 반복해서 붙일 수 있음
@Repeatable 하나로 묶을 컨테이너 애너테이션도 정의해야함
애너테이션 타입 정의하기
- 애너테이션을 직접 만들어 사용할 수 있음
@interface 애너테이션이름{
타입 요소이름(); //애너테이션의 요소를 선언
...
}
//ex)
@interface DateTime{
String yymmdd();
String hhmmss();
}
- 애너테이션의 메소드는 추상 메소드이며, 애너테이션을 적용할 때 지정(순서가 없음)
enum TestType{FIRST, FINAL}
@interface TestInfo{
int count();
String testedBy();
String[] testTools();
TestType testType(); //enum TestTpye{FIRST, FINAL}
DateTime testDate(); //자신이 아닌 다른 애너테이션(@DateTime)을 포함할 수 있음
}
@TestInfo(
count=3,
testedBy="Kim",
testTools={"JUnit","AutoTester"},
testType=TestType.FIRST,
testDate=@DateTime(yymmdd="240820", hhmmss="165000")
)
애너테이션의 요소
- 적용 시 값을 지정하지 않으면, 사용 될 수 있는 기본값 지정 가능(null 제외)
@interface TestInfo1{
int count() default 1; //기본값을 1로 지정
}
@TestInfo1 //@TestInfo1(count=1)과 동일. default값이 있는경우 생략가능
- 요소가 하나이고 이름이 value일 때는 요소 이름 생략가능
@interface TestInfo2{
String value();
}
@TestInfo2("passed") //@TestInfo(value="passed")와 동일
- 요소의 타입이 배열인 경우, 괄호{}를 사용
@interface TestInfo3{
String[] testTools();
}
//@TestInfo3(testTools={"passed"}) //값이 하나일 경우 @TestInfo3(testTools="passed")와 같이 {} 생략가능
//@TestInfo3(testTools={"Tester1","Tester2"})
@TestInfo3(testTools= {}) //값이 없을 때 {} 반드시 필요
모든 애너테이션의 조상
java.lang.annotation.Annotation
- Annotation은 모든 애너테이션의 조상이지만 상속은 불가
- Annotation은 인터페이스
추상메소드를 가지고 있음. 구현할 필요는 없지만 사용 가능
@interface TestInfo4 extends Annotation{} //에러. 허용되지 않은 표현
마커 애너테이션
- 요소가 하나도 정의되지 않은 애너테이션
ex) @Deprecated
애너테이션 요소의 규칙
- 요소의 타입은 기본형, String, enum, 애너테이션, Class(Class 클래스)만 허용
- 괄호() 안에 매개변수를 선언할 수 없음
- 예외를 선언할 수 없음
- 요소를 타입 매개변수로 정의할 수 없음
package chapter12;
import java.lang.annotation.*;
@Deprecated
@SuppressWarnings("1234") //유효하지 않은 애너테이션은 무시됨
@chapter12.Study13.TestInfo(testedBy="abc", testDate=@chapter12.Study13.DateTime(yymmdd="240820", hhmmss="161500"))
public class Study13 {
public static void main(String[] args) {
Class<Study13> cls = Study13.class; //Study13의 Class객체를 얻음
TestInfo anno = cls.getAnnotation(TestInfo.class);
System.out.println("anno.testedBy() = " + anno.testedBy());
System.out.println("anno.testDate().yymmdd() = " + anno.testDate().yymmdd());
System.out.println("anno.testDate().hhmmss() = " + anno.testDate().hhmmss());
for(String str:anno.testTools()) {
System.out.println("testTools = " + str);
}
System.out.println();
Annotation[] annoArr = cls.getAnnotations(); //현재 클래스에 적용된 모든 애너테이션을 가져옴
for(Annotation annotation : annoArr) {
System.out.println(annotation);
}
}
@Retention(RetentionPolicy.RUNTIME) //실행 시에 사용 가능하도록 지정
@interface TestInfo{
int count() default 1;
String testedBy();
String[] testTools() default "JUnit";
TestType testType() default TestType.FIRST;
DateTime testDate();
}
@Retention(RetentionPolicy.RUNTIME) //실행 시 사용 가능하도록 지정
@interface DateTime{
String yymmdd();
String hhmmss();
}
enum TestType{FIRST,FINAL}
}
728x90