Contents
Annotation 간략히 정리
   Aug 16, 2022     9 min read

애너테이션

애너테이션이란 ?

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

예전에 …

.java 파일

java 파일 문서

파일 변경 & 문서변경 → 안할 시 → 관리가안됨..

그래서 source code + document 파일 = 애너테이션

javadoc.exe가 주석을 추출 → 문서를 만들어낸다.

/**
*
*/

소스 코드 , 설정 파일(XML..)

따로 분리되어 있었음..

  • xml 단점 : 여러사람이 공유 …

소스코드 + 설정파일

설정 파일을 '@'애너테이션 특정프로그램에서만 정보 제공(설정 정보)

Untitled

문서 + source code = 애너테이션

표준 애너테이션

애너테이션설명
@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() // 오버라이딩하려 했으나 실수로 이름을 잘못적음
}
  • 오버라이딩할 때는 메서드 선언부 앞에 @Override
class Child extends Parent{
	void parentmethod(){}
}

👇👇👇

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

@Override를 붙이면 에러가 나오게 됨으로써 실수를 찾아낼 수 있다.

@Deprecated

  • 앞을 사용하지 않을 것을 권장하는 필드나 메서드에 붙인다.
  • @Deprecated의 사용 예, Date클래스의 getDate()
@Deprecated
public int getDate(){
	return normalize().getDayOfMonth();
}

Java API 문서에 이렇게 써있다.

Untitled 1

Untitled 2

javac로 컴파일 해보자.

Untitled 3

경고가 뜬다.

Untitled 4

@FunctionalInterface

  • 컴파일러가 사용하는 애너테이션
  • 함수형 인터페이스에 붙이면, 컴파일러가 올바르게 작성했는지 확인한다.

참고 : 함수형 인터페이스에는 하나의 추상메서드만 가져야 한다는 제약이 있다.

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

추상메서드가 0개, 2개 이상일 경우 에러가난다. 에러를 알아차리는 것은 FunctionalInterface 때문이다.

@ SuppressWarnings

  • 컴파일러의 애너테이션
  • 컴파일러의 경고메시지가 나타나지 않게 억제한다.
  • 붙이는 이유는 나오는 경고를 확인했다는 의미이다.
@SuppressWarnings("unchecked") // 지네릭스와 관련된 경고를 억제
ArrayList list = new ArrayList(); // 지네릭 타입을 지정하지 않았다.
list.add(obj) // 여기서 경고가 발생한다.

  • 둘 이상의 경고를 동시에 억제하려면
@SuppressWarnings( { "deprecation", "unchecked", "varargs") }
  • ‘-Xlint’옵션으로 컴파일하면, 경고메시지를 확인할 수 있다. 괄호 [ ] 안이 경고의 종류. 아래의 경우 rawtypes

경고를 처리하지 않으면 계속 쌓여서 새로 발생된 경고를 발견하지 못할 수 도 있다.

메타 애너테이션

  • 메타 애너테이션은 ‘애너테이션을 위한 애너테이션’
  • 메타 애너테이션은 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[] valus();
}
대상타입의미
ANNOTATION_TYPE애너테이션
CONSTRUCTOR생성자
FIELD필드(멤버변수, enum상수)
LOCAL_VARIABLE지역변수
METHOD메서드
PACKAGE패키지
PARAMETER매개변수
TYPE타입(클래스, 인터페이스, enum)
TYPE_PARAMETER타입 매개변수(JDK1.8)
TYPE_USE타입이 사용되는 모든 곳(JDK1.8)
@Target({FIELD, TYPE, TYPE_USE]) // 적용대상이 FIELD, TYPE, TYPE_USE
public @interface MyAnnotation{ } // MyAnnotation을 정의

@MyAnnotation // 적용대상이 TYPE인 경우

class Myclass{
	@MyAnnotation // 적용대상이 FIELD인 경우
	int i; //

	@MyAnnotation // 적용대상이 TYEP_USE인 경우
	MyClass mc;
}

@Retention

  • 애너테이션이 유지(Retention)되는 기간을 지정하는데 사용
유지 정책의미
SOURCE소스 파일(.java)에만 존재. 클래스파일에는 존재하지 않음
CLASS클래스 파일에 존재. 실행시에 사용불가. 기본값
RUNTIME클래스 파일에 존재. 실행시에 사용가능.
  • 컴파일러에 의해 사용되는 애너테이션의 유지 정책은 SOURCE이다.
@Target(ElementType.METHOD)
@RETENTION(RETENTIONPOLICY.SOURCE)
public @interface Override {}

@Override 는 오버라이딩 체크 (컴파일러)

  • 실행 시에 사용 가능한 애너테이션의 정책은 RUNTIME이다.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface{ }

클래스파일까지 존재한다고 하면 소스파일에도 존재한다는 것이다.

@Documented, @Inherited

  • javadoc으로 작성한 문서(*.html)에 포함시키려면 @Documented를 붙인다.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface{ }
  • 애너테이션을 자손 클래스에 상속하고자 할 때, @Inherited를 붙인다.
@Inherited //@SuperAnno가 자손까지 영향 미치게
@interface SuperAnno{ }

@SuperAnno
class Parent{}

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

SuperAnno 조상 애너테이션

//@SuperAnno <- 붙은 것과 같은 효과가 난다.
class Child extends Parent{ }

조상의 애너테이션이 자손까지 상속됨

많이 사용하지 않기 때문에 이런게 있구나 하고 넘어가자

@Repeatable

  • 반복해서 붙일 수 있는 애너테이션을 정의할 때 사용
@Repeatable(ToDos.class) // ToDo 애너테이션을 여러 번 반복해서 쓸 수 있게 한다.
@interface ToDo{
	String value();
}
  • @Repeatable이 붙은 애너테이션은 반복해서 붙일 수 있다.
@ToDo("delete test codes.")
@ToDo("override inherited methods")
class MyClass{
		.....
}
  • @Repeatable인 @ToDo를 하나로 묶을 컨테이너 애너테이션도 정의해야 함
@intgerface ToDos{ // 여러 개의 ToDo애너테이션을 담을 컨테이너 애너테이션 ToTDos
	@interface ToDos{ //Todo애너테이션 배열타팁의 요소를 선언. 이름은 반드시 value이어야함
		ToDo[] value();//
	}

}

애너테이션 타입 정의하기

  • 애너테이션을 직접 만들어 쓸 수 있다.
@interface 애너테이션이름{
타입 요소이름(); // 애너테이션의 요소를 선언한다.
		
}
@interface DateTime{

	String yymmdd();
	String hhmmss();
}

2개의 요소 : String yymmdd(); String hhmmss();

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

  • TestInfo라는 애너테이션 생성

@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{ ...}
  • 순서 X
  • 추상메서드 구현 X

애너테이션의 요소

  • 적용시 값을 지정하지 않으면, 사용될 수 있는 기본 값 지정 가능(null 제외)
@interface TestInfo{
		int count() default 1; // 기본값을 1로 지정
}

@TestInfo // @TestInfo(count = 1) 과 동일
public class NewClass{ ....}
  • 요소가 하나이고 이름이 value일 때는 요소의 이름 생략 가능
@interface TestInfo{
	String value();
}

@TestInfo("passed") // @TestInfo(value = "passed")와 동일
class NewClass { ... }
  • 요소의 타입이 배열인 경우, 괄호{}를 사용해야 한다.
@interface TestInfo{
	String[] testTools();
}
@Test(testTools={"JUnit", "AutoTester"})
@Test(testTools= "JUnit")
@Test(testTools={ }) // 값이 없을 때는 괄호 {}가 반드시 필요

모든 애너테이션의 조상

  • Annotation은 모든 애너테이션의 조상이지만 상속은 불가
@interface TestInfo extends Annotation{ // 에러. 허용되지 않는 표현
	int count();
	String testedBy();
	...
}
  • 사실 Annotation은 인터페이스이다.
public interface Annotation{ // Annotation자신은 인터페이스이다.
	boolean equals(Object obj); //추상메서드
	int hashcode(); // 추상메서드
	String toString(); // 추상메서드

	Class<? extends Annotation> annotationTyep(); // 애너테이션의 타입을 반환
}

마커 애너테이션 - Marker Annotation

  • 요소가 하나도 정의되지 않은 애너테이션
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {} // 마커 애너테이션. 정의된 요소가 하나도 없다.

@Target(ElementType.METHOD)
@Retention(RetentionPoilcy.SOURCE)
public @interface Test{} // 마커 애너테이션. 정의된 요소가 하나도 없다.

예시)

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

애너테이션 요소의 규칙

  • 애너테이션의 요소를 선언할 때 아래의 규칙을 반드시 지켜야 한다
    • 요소의 타입은 기본형, String, enum, 애너테이션, Class만 허용 됨
    • 괄호()안에 매개변수를 선언할 수 없다.
    • 예외를 선언할 수 없다.
    • 요소를 타입 매개변수로 정의할 수 없다.
  • 아내의 코드에서 잘못된 부분을 무엇인지 생각해보자.
@interface Annotaion{
	int id = 100; // static final (생략), 상수 OK, default메서드 (X)
	String major(int i, int j); // 매개변수 에러 x
	String minor() throws Exception; //예외 선언 x
	ArrayList<T> list; //에러
}

참고 : 자바의 정석