12장 애너테이션

slee2·2021년 9월 23일
0

Java의 정석

목록 보기
24/28
post-thumbnail
post-custom-banner

애너테이션이란?

주석처럼 프로그래밍 언어에 영향을 미치지 않으며, 유용한 정보를 제공

애너테이션 사용 예

@Test	// 이 메서드가 테스트 대상임을 테스트 프로그램에게 알린다.(이게 애너테이션)
public void method() {
	...
}

표준 애너테이션

Java에서 제공하는 애너테이션

애너테이션설명
@Override컴파일러에게 오버라이딩하는 메서드라는 것을 알린다.
@Deprecated앞으로 사용하지 않을 것을 권장하는 대상에 붙인다.
@SuppressWarnings컴파일러의 특정 경고메시지가 나타나지 않게 해준다.
@SafeVarargs지네릭스 타입의 가변인자에게 사용한다.(JDK1.7)
@FunctionalInterface함수형 인터페이스라는 것을 알린다.(JDK1.8)
@Nativenative메서드에서 참조되는 상수 앞에 붙인다.(JDK1.8)
@Target*애너테이션이 적용가능한 대상을 지정하는데 사용한다.
@Documented*애너테이션 정보가 javadoc으로 작성된 문서에 포함되게 한다.
@Inherited*애너테이션이 자손 클래스에 상속되도록 한다.
@Retention*애너테이션이 유지되는 범위를 지정하는데 사용한다.
@Repeatable*애너테이션을 반복해서 적용할 수 있게 한다.(JDK1.8)

*가 붙은 것은 메타 애너테이션

@Override

오버라이딩을 올바르게 했는지 컴파일러가 체크하게 한다.
오버라이딩할 때 메서드 이름을 잘못적는 실수를 하는 경우가 많다.

class Parent {
	void parentMethod() {}
}

class Child extends Parent {
	void parentmethod() {}	// 오버라이딩하려 했으나 이름을 실수로 잘못적음
}

이를 방지하기 위해

class Parent {
	void parentMethod() {}
}

class Child extends Parent {
	@Override
   	void parentmethod() {}
}


오버라이딩이 아니라고 알려줌.

@Deprecated

앞으로 사용하지 않을 것을 권장하는 필드나 메서드에 붙인다.

사용 예

옛날꺼라 문제가 생길수도 있으니 웬만하면 사용하지 않는것을 권장하도록 @Deprecated가 붙는다.

@Deprecated
public int getDate() {
	return normalize().getDayOfMonth();
}


@Deprecated가 붙은 대상이 사용된 코드를 컴파일하면 에러는 아니지만 경고가 나타난다.

@FunctionalInterface

함수형 인터페이스에 붙이면, 컴파일러가 올바르게 작성했는지 체크(14장에 있으니 자세한 설명은 생략)
함수형 인터페이스에는 하나의 추상메서드만 가져야 한다는 제약이 있음

@FunctionalInterface
public interface Runnable {
	public abstract void run();	// 추상메서드 1개
}

@SuppressWarnings

컴파일러의 경고메시지가 나타나지 않게 억제한다.
괄오() 안에 억제하고자 하는 경고의 종류를 문자열로 지정

@SuppressWarnings("unchecked")		// 지네릭스와 관련된 경고를 억제
ArrayList list = new ArrayList();	// 지네릭 타입을 지정하지 않았음.
list.add(obj);				// 여기서 경고가 발생

여러개를 쓰고 싶으면

@SuppressWarnings({"unchecked", "deprecation"})

'-Xlint'옵션으로 컴파일하면, 경고메시지를 확인할 수 있다.

@SuppressWarnings를 쓰는 이유 - 경고를 이미 알고 있고 확인했다는 신호

메타 애너테이션

애너테이션을 위한 애너테이션
메타 애너테이션은 java.lang.annotation 패키지에 포함

애너테이션설명
@Target애너테이션이 적용가능한 대상을 지정하는데 사용한다.
@Documented애너테이션 정보가 javadoc으로 작성된 문서에 포함되게 한다.
@Inherited애너테이션이 자손 클래스에 상속되도록 한다.
@Retention애너테이션이 유지되는 범위를 지정하는데 사용한다.
@Repeatable애너테이션을 반복해서 적용할 수 있게 한다.(JDK1.8)

@Target

애너테이션을 정의할 때, 적용대상 지정에 사용

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
	String[] value();
}
대상타입의미
ANNOTATION_TYPE애너테이션
CONSTRUCTOR생성자
FIELD필드(멤버변수, enum상수)
LOCAL_VARIABLE지역변수
METHOD메서드
PACKAGE패키지
PARAMETER매개변수
TYPE타입(클래스, 인터페이스, enum)
TYPE_PARAMETER타입 매개변수(JDK1.8)
TYPE_USE타입이 사용되는 모든 곳(JDK1.8)

예시

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

@MyAnnotation	// 적용대상이 TYPE인 경우
class MyClass {
	@MyAnnotation	// 적용대상이 FIELD인 경우
   	int i;
    
   	@MyAnnotation	// 적용대상이 TYPE_USE인 경우
   	MyClass mc;
}

@Retention

애너테이션이 유지(retention)되는 기간을 지정하는데 사용

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

컴파일러에 의해 사용되는 애너테이션의 유지 정책은 SOURCE이다.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {}

Override는 오버라이딩을 했는가 체크하는 애너테이션이다. 이는 컴파일러가 체크하고 끝나서 실행할때는 필요 없기 때문에 SOURCE로 소스 파일에만 존재하게 하는 것이다.

실행시에 사용가능한 애너테이션의 정책은 RUNTIME이다.

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

실행까지 간다.

@Documented, @Inherited

javadoc으로 작성한 문서에 포함시키려면 @Documented를 붙인다.
우리가 쓸일은 없기때문에 넘어감

애너테이션을 자손 클래스에 상속하고자 할 때, @Inherited를 붙인다.

@Ingerited			// @SuperAnno가 자손까지 영향 미치게
@interface SuperAnno {}

@SuperAnno
class Parent {}

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

둘다 많이 사용하는것은 아니라 알아두는 정도로만

@Repeatable

반복해서 붙일 수 있는 애너테이션을 정의할 때 사용

@Repeatable(ToDos.class)
@interface ToDo {
	String value();
}

---@Repeatable@ToDo를 하나로 묶을 컨테이너 애너테이션도 정의해야 함.---

@interface ToDos {	// 여러개의 ToDo애너테이션을 담을 컨테이너 애너테이션 ToDos
	ToDo[] value();	// ToDo애너테이션 배열타입의 요소를 선언. 이름이 반드시 value이어야 함
}

---이렇게 하면 여러번 사용 가능---

@ToDo("delete test codes.")
@ToDo("override inherited methods")
class MyClass {
	...
}

많이 안쓰니 알아만 두자

애너테이션 타입 정의하기

애너테이션을 직접 만들어 쓸 수 있다.

@interface 애너테이션이름 {
	타입 요소이름();	// 애너테이션의 요소를 선언한다.
   		...
}
@interface DateTime {
	String yymmdd();
   	String hhmmss();
}

애너테이션의 메서드는 추상메서드이며, 애너테이션을 적용할 때 지정(순서X)

@interface TestInfo {
	int count();
   	String testedBy();
   	String[] testTools();
   	TestType testType();	// enum TestType {FIRST, FINAL}
   	DateTime testDate();	// 자신이 아닌 다른 애너테이션(@DateTime)을 포함할 수 있다.
}
--- 요소의 이름과 맞게 전부 설정해 줘야 한다. ---
@TestInfo(
	count=3, testedBy="Kim",
   	testTools={"JUnit", "AutoTester"},
   	testType=TestType.FIRST,
   	testDate=@DateTime(yymmdd="160101", hhmmss="235959")
)
public class NewClass { ... }

애너테이션의 요소

적용시 값을 지정하지 않으면, 사용될 수 있는 기본값 지정 가능(null제외)

@interface TestInfo {
	int count() default 1;	// 기본값을 1로 지정
}
@TestInfo	// @TestInfo(count=1)과 동일

요소가 하나이고 이름이 value일 때는 요소의 이름 생략가능

@interface TestInfo {
	String value();
}
@TestInfo("passed")	// @TestInfo(value="passed")와 동일

요소의 타입이 배열인 경우, 괄호{}를 사용해야 한다.

@interface TestInfo {
	String[] testTools();
}
@Test(testTools={"JUnit", "AutoTester"})
@Test(testTools="JUnit")
@Test(testTools={})	// 값이 없을 때는 괄호{}가 반드시 필요

모든 애너테이션의 조상

사실 Annotation은 인터페이스이다. 상속은 불가

package java.lang.annotation;

public interface Annotation {	// Annotation자신은 인터페이스이다.
	boolean equals(Object obj);
   	int hashCode();
   	String toString();
    
   	Class<? extands Annotation> annotationType();	// 애너테이션의 타입을 반환
}

마커 애너테이션 - Maker Annotation

요소가 하나도 정의되지 않은 애너테이션

@Test	// 이 메서드가 테스트 대상임을 테스트 프로그램에게 알린다.
public void method() {
	...
}

요소가 없으니까 그냥 저렇게 쓰면 된다. 마커 애너테이션은 그냥 말로 부르고 다니는것 딱히 의미는 없다.

애너테이션 요소의 규칙

요소의 타입은 기본형, String, enum, 애너테이션, Class만 허용됨

괄호() 안에 매개변수를 선언할 수 없다.

예외를 선언할 수 없다.

요소를 타입 매개변수로 정의할 수 없다.(<T> 요런거)

post-custom-banner

0개의 댓글