[Java] annotation

eeminsu·2021년 11월 25일
0
post-thumbnail

자바의 정석을 통해 공부한 내용을 요약하였습니다

1. 애너테이션이란?

  • 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것
  • 주석처럼 프로그래밍 언어에 영향을 미치지 않으면서도 다른 프로그램에게 유용한 정보를 제공할 수 있는 장점이 있다.
@Test // 이 메서드가 테스트 대상임을 테스트 프로그램에게 알림
public void method() {
	....
}
  • 예를 들어 위 처럼 '@Test' 애너테이션을 사용하면 해당 메서드를 테스트 해야 한다는 것을 테스트 프로그램에게 알리는 역할을 하게 된다.
    메서드가 포함된 프로그램 자체에는 아무런 영향을 미치지 않는다.


2. 표준 애너테이션

  • 자바에서 기본적으로 제공하는 애너테이션이다.

2-1. @Override

class Parent {
	void parentMethod() { }
}

class Child extends Parent {
	@Override
	void parentmethod() { } // 조상 메서드의 이름을 잘못적었음. 에러 발생
}
  • 조상의 메서드를 오버라이딩 하는 것이라는 걸 컴파일러에게 알려주는 역할을 한다.
  • 메서드 앞에만 붙일 수 있다.
  • 컴파일러가 같은 이름의 메서드가 조상에 있느지 확인하고 없으면, 에러메시지를 출력한다.

2-2. @Deprecated

@Deprecated
int oldField;

@Deprecated
int getOldField() { 
	return oldField;
}
  • 해당 대상이 다른 것으로 대체되어 더 이상 사용하지 않는 것을 권하는 애너테이션이다.
  • 하위 호환성을 고려하여 기존의 것도 사용 가능하나 개선된 기능을 사용하도록 유도하는 것이다.
  • 컴파일을 하게 되면 경고메시지가 나오게 되며 '-Xlint:deprecation'을 붙여서 컴파일을 하게 되면 자세한 내용을 알 수 있다.

2-3. @FunctionalInterface

@FunctionalInterface
public interface Runnable {
	void run(); // 추상 메서드
}
  • 컴파일러가 함수형 인터페이스를 올바르게 선언했는지 확인하고 잘못된 경우 에러를 발생
  • 함수형 인터페이스는 추상 메서드가 한 개만 있어야 하므로 2개 이상이거나 하나도 없을 때 에러가 발생한다.

2-4. @SuppressWarnings

@SuppressWarnings("unchecked")               // 지네릭스 관련 경고를 억제
ArrayList<NewClass2> list = new ArrayList();  // 타입을 지정하지 않음.
list.add(nc);
  • 컴파일러가 보여주는 경고메시지가 나타나지 않게 억제해준다.
  • 억제하려는 경고 메시지를 애너테이션의 뒤에 ()안에 문자열로 지정하면 된다.
  • 둘 이상의 메시지는 {}를 사용한다.
  • 메서드 선언 뿐 아니라 메서드가 호출되는 곳에도 에너테이션을 붙여주어야 한다.
  • 경고가 발생할 것을 알면서도 묵인할 때 사용한다.
  • 해당 메서드가 발생시키는 경고를 알고있다는 의미로 사용되는 것이다.
  • 새로운 경고 메시지를 발견하지 못하는 것을 방지할 수 있다.

주로 사용되는 경고 메시지

  • deprecation : @Deprecated가 붙은 대상을 사용해서 발생하는 경고
  • unchecked : 지네릭스로 타입을 지정하지 않았을 때 발생하는 경고
  • rawtypes : 지네릭스를 사용하지 않아서 발생하는 경고
  • varargs : 가변인자의 타입이 지네릭 타입일 때 발생하는 경고


3. 메타 에너테이션

  • 자바가 제공하는 표준 애너테이션이자 애너테이션을 위한 애너테이션이다.
  • 애너테이션을 정의할 때 애너테이션의 적용대상(Target)이나 유지기간(retention)등을 지정하는데 사용된다.

3-1. @Target

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@interface DateTime {
	String yymmdd();
	String hhmmss();
}
  • 애너테이션이 적용가능한 대상을 지정하는데 사용된다.


3-2. @Retention

  • 애너테이션이 유지되는 기간을 지정하는데 사용된다.
  • SOURCE의 예 : @Override, @SuppressWarnings 등등
  • RUNTIME의 예 : @FunctionalInterface 등

3-3. @Documented

  • 애너테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다.

3-4. @Inherited

  • 애너테이션이 자손 클래스에 상속되도록 한다.
  • @Inhertied가 붙은 애너테이션을 조상 클래스에 붙이면 자손클래스도 이 애너테이션이 붙은 것과 같이 인식된다.

3-5. @Repeatable

  • 보통 하나의 대상에 한 종류의 애너테이션을 붙이는데 '@Repeatable'이 붙은 애너테이션은 여러번 붙일 수 있다.
@interface ToDos { // 여러 개의 ToDo애너테이션을 담을 컨테이너 애너테이션
	ToDo[] value(); // ToDo 애너테이션 배열타입의 요소를 선언, 이름은 반드시 value여야 함
}
  • 일반적인 애너테이션과 달리 같은 이름의 애너테이션이 여러 개가 하나의 대상에 적용될 수 있기 때문에 하나로 묶어서 다룰 수 있는 애너테이션도 추가로 정의해야 한다.


4. 애너테이션 타입 정의

@interface 애너테이션이름 {
타입 요소이름();
....
}

  • '@'기호를 붙이는 것을 제외하면 인터페이스를 정의하는 것과 동일하다.

4-1. 애너테이션의 요소

@interface TestInfo {
	int       count()	    default 1; // 기본 값을 가질 수 있다.
	String    testedBy();
	String[]  testTools()   default "JUnit";
	TestType  testType()    default TestType.FIRST;
	DateTime  testDate();
}

@interface DateTime {
	String yymmdd();
	String hhmmss();
}

@TestInfo(testedBy="aaa", testDate=@DateTime(yymmdd="160101", hhmmss="235959"))
  • 반환값이 있고 매개변수는 없는 추상 메서드의 형태이며 상속을 통해 구현하지 않아도 된다.
  • 애너테이션을 적용할 때 이 요소들의 값을 빠짐없이 지정해주어야 한다.
  • 요소의 이름도 같이 적어주므로 순서는 상관 없다.
  • 각 요소는 default를 이용하여 기본 값을 가질 수 있다.
  • 요소가 오직 하나 뿐이고 이름이 value인 경우 애너테이션 적용시 이름을 생략하고 값만 적을 수 있다.
  • 요소의 타입이 배열인 경우 {}를 사용해서 여러 개의 값을 지정할 수 있다, 기본 값을 지정할 때도 가능하다.
    예) @SuppressWarnings

4-2. java.lang.annotation.Annotation

public interface Annotation { // Annotation 자신은 인터페이스이다.
	boolean equals(Object obj);
    int hashCode();
    String toString();
    
    Class<? extends Annotation> annotationType(); // 애너테이션 타입 반환
}
  • 모든 애너테이션의 조상은 Annotation이다.
  • 명시적으로 Annotation을 조상으로 지정할 수 없다.
  • 모든 애너테이션 객체는 equals(), hashCode(), toString()과 같은 메서드를 호출하는 것이 가능하다.

4-3. Marker Annotation

  • 애너테이션의 요소를 하나도 정의하지 않을 수있다.
  • 요소가 하나도 정의되지 않은 애너테이션을 마커 애너테이션이라 한다.
  • 예)
public @interface Override {}
public @interface Test {}

4-4. 애너테이션 요소의 규칙

  • 요소의 타입은 기본형, String, enum, 애너테이션, Class만 허용
  • ()안에 매개변수를 선언할 수 없음
  • 예외를 선언할 수 없음
  • 요소를 타입 매개변수로 정의할 수 없음
@interface AnnoTest {
	int id = 100; // OK
    String major(int i, int j); // 에러, 매개변수 선언 불가능
    String minor() throws Exception; // 에러, 예외 선언 불가능
    ArrayList<T> list(); // 에러, 요소의 타입에 타입 매개변수 사용 불가능
}
profile
안되면 될 때까지

0개의 댓글