애너테이션(annotation)

Sangwon Na·2021년 9월 13일
0

1. 애너테이션

  • 애너테이션은 코드 앞에 붙여서 특별한 의미를 부여하는 기능입니다.
  • 주석처럼 프로그래밍 언어에 영향을 미치지 않으면서, 다른 프로그램에게 유용한 정보를 제공 합니다.
@Test // 애너테이션 선언 - 테스트 대상임을 알림
public void method() {
	...
}

2. 표준 애너테이션

표준 애너테이션은 Java에서 제공하는 애너테이션입니다.

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

🍉 @Override

  • 오버라이딩을 올바르게 했는지 컴파일러가 체크합니다.
class Parent {
	void parentMethod() {} // M - m 대소문자가 오타
}

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

class Child extends Parent {
	@Override
	void parentmethod() { } // 조상 메서드의 이름을 잘못적었음. 
}

🍉 @Deprecated

  • @Deprecated는 앞으로 사용하지 않을 것을 권장하는 대상에 붙인다.
  • @Deprecated가 붙은 대상을 사용하는 코드를 작성하고 컴파일하면 나타나는 메시지는 아래와 같다.
class Personnel{
	@Deprecated
	String name; // name 의 더이상 사용을 금지시킨다.
	int age;
	void ovt() {
		System.out.println("오버라이딩 테스트");
	}
}

🍉 @SuppressWarnings

  • @SuppressWarnings는 컴파일러의 경고 메시지가 나타나지 않게 억제한다.

  • @SuppressWarnings로 억제 할 수 있는 경고 메시지 중 자주 사용되는 것은 아래와 같다.
    ① deprecation : @Deprecated가 붙은 대상을 사용해서 발생하는 경고를 억제할 때 사용한다.
    ② unchecked : 제네릭으로 타입을 지정하지 않았을 때 발생하는 경고를 억제할 때 사용한다.
    ③ rawtypes : 제네릭을 사용하지 않아서 발생하는 경고를 억제할 때 사용한다.
    ④ varargs : 가변 인자의 타입이 제네릭 타입일 때 발생하는 경고를 억제할 때 사용한다.

  • 괄호() 안에 억제 하고자 하는 경고 메시지의 종류를 문자열로 지정한다.

@SuppressWarnings("unchecked") // 제네릭과 관련된 경고를 억제
ArrayList list = new ArrayList(); // 제네릭 타입을 지정하지 않았음
list.add(obj);
  • 둘 이상의 경고를 동시에 억제하려면 다음과 같이 한다.
@SuppressWarnings({"deprecation", "unchecked", "varargs"})

🍉 @FunctionalInterFace

  • @FuntionalInterface는 함수형 인터페이스를 올바르게 작성했는지 컴파일러가 체크하게 한다. (함수형 인터페이스는 하나의 추상 메서드만 가져야 한다는 제약이 있음)
@FunctionalInterface
public interface Runnable{
	public abstract void run(); // 추상 메서드
}

🍉 @Navtive

  • @Native는 native 메서드에 의해 참조되는 상수에 붙이는 애노테이션이다.
@Native public static final long MIN_VALUE = 0x8000000000000000L;
  • 네이티브 메서드는 JVM이 설치된 OS의 메서드를 말한다.
    네이티브 메서드는 보통 C 언어로 작성되어 있는데, 자바에서는 메서드의 선언부만 정의하고 구현은 하지 않는다.

  • 자바에 정의된 네이티브 메서드와 OS의 메서드를 연결해주는 작업은 JNI(Java Native Interface)가 담당한다.


3. 메타 에너테이션

  • 애너테이션을 정의 하는데 사용되는 애너테이션입니다.

🍉 @Target

  • @Target은 애노테이션이 적용 가능한 대상을 지정하는데 사용된다.
  • 여러 개의 값을 지정할 때는 배열에서 처럼 괄호 {}를 사용해야 한다.
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}
  • @Target으로 지정 할 수 있는 애노테이션 적용 대상의 종류는 다음과 같다.
대상 타입의미
ANNOTATION_TYPE애노테이션
CONSTRUCTOR생성자
FIELD필드(멤버 변수, enum 상수)
LOCAL_VARIABLE지역변수
METHOD메서드
PACKAGE패키지
PARAMETER매개변수
TYPE타입 (클래스, 인터페이스, enum)
TYPE_PARAMETER타입 매개변수(JDK 1.8)
TYPE_USE타입이 사용되는 모든 곳 (JDK 1.8)

@Retention

  • @Retention은 애노테이션이 유지(retention)되는 기간을 지정하는데 사용된다.
유지 정책의미
SOURCE소스 파일에만 존재. 클래스 파일에는 존재하지 않음
CLASS클래스 파일에 존재. 실행 시에 사용 불가. 기본 값
RUNTIME클래스 파일에 존재. 실행 시에 사용 가능
  • 컴파일러에 의해 사용되는 애노테이션의 유지 정책은 SOURCE이다.




🍉 @Documented

  • @Documented는 애노테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

🍉 @Inherited

  • @Inherited는 애노테이션이 자손 클래스에 상속 되도록 한다.
  • @Inherited가 붙은 애노테이션을 조상 클래스에 붙이면, 자손 클래스도 이 애노테이션이 붙은 것과 같이 인식된다.
@Inherited // @SupperAnno가 자손까지 영향 미치게
@interface SupperAnno {}

@SuperAnno
class Parent {}

class Child extends Parent {} // Child에 애노테이션이 붙은 것으로 인식한다.

🍉 @Repeatable

  • @Repeatable는 반복해서 붙일 수 있는 애노테이션을 정의할 때 사용한다.
@interface ToDos{ // 여러 개의 ToDo 애노테이션을 담을 컨테이너 애노테이션 ToDos
	ToDo[] value(); // ToDo 애노테이션 배열 타입의 요소를 선언. 이름이 반드시 value 이어야 함 
}

// ToDo 애노테이션을 여러 번 반복해서 쓸 수 있게 한다.
@Repeatable(ToDos.class) // 괄호 안에 컨테이너 애노테이션을 지정해 줘야한다.
@interface ToDo {
	String value();
}
  • @Repeatable이 붙은 애너테이션은 반복해서 붙일 수 있다.
@ToDo("delete test codes.")
@ToDo("override inherited methods")
class MyClass {
	...
}

4. 에너테이션 타입 정의 하기

⭕ 새로운 애노테이션을 정의하는 방법

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

⭕ 애노테이션의 요소

  • 애노테이션의 요소(element)는 애노테이션 내에 선언된 메서드를 말한다.
  • 아래에 선언된 TestInfo 애노테이션은 다섯 개의 요소를 갖는다.
@interface TestInfo {
	int       count();
	String    testedBy();
	String[]  testTools();
	TestType  testType(); // enum TestType { FIRST , FINAL }
	DateTime  testDate(); // 자신이 아닌 다른 애노테이션(@DateTime)을 포함 할 수 있다.
}

@interface DateTime {
	String yymmdd();
	String hhmmss();
}
  • 애노테이션의 요소는 반환 값이 있고, 매개 변수는 없는 추상 메서드의 형태를 가진다.

    그리고 애노테이션을 적용할 때 이 요소들의 값을 모두 지정 해야 한다. (요소의 이름도 같이 적어주므로 순서는 상관 없다.)

@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;

}

@TestInfo // @TestInfo(count = 1)과 동일 
public class NewClass { ... }
 
  • 애노테이션의 요소가 하나이고 이름이 value인 경우, 애노테이션을 적용할 때 요소의 이름을 생략 하고 값만 적어도 된다.
@interface TestInfo {
	String value();
}

@TestInfo("passed") // @TestInfo (value="passed")와 동일
public class NewClass { ... }
  • 요소의 타입이 배열인 경우, 중괄호 {}를 사용해서 여러 개의 값을 지정할 수 있다.
@interface TestInfo {
    String[] testTools();
}


@TestInfo(testTools = {"JUnit", "AutoTester"}) // 값이 여러 개 인 경우
@TestInfo(testTools = "JUnit") // 값이 하나일 때는 괄호 {} 생략 가능
@TestInfo(testTools = {}) // 값이 없을 때는 괄호 {}가 반드시 필요
class NewClass { ... }
  • 기본 값을 지정할 때도 괄호{}를 사용할 수 있다.
@interface TestInfo {
    String[] info() default {"aaa", "bbb"}; // 기본 값이 여러 개인 경우, 괄호 {} 사용
    String[] info2() default "ccc"; // 기본 값이 하나 인 경우, 괄호 생략 가능
}

@TestInfo // @TestInfo (info={"aaa", "bbb"}, info2="ccc")와 동일 
@TestInfo(info2={}) // @TestInfo (info={"aaa", "bbb"}, info2={})와 동일 
class NewClass { ... }





java.lang.annotation.Annotation

⭕ Annotation은 모든 애노테이션의 조상이지만 상속은 불가능하다.

@interface TestInfo extends Annotation { // 에러. 허용되지 않는 표현
    int count();
    String testedBy();
    . . .
}
  • 사실, Annotation은 인터페이스로 정의되어 있다.

⭕ 마커 애노테이션 (Marker Anntation)

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

⭕ 애노테이션 요소의 규칙

  • 애노테이션의 요소를 선언할 때 지켜야 하는 규칙은 다음과 같다.

① 요소의 타입은 기본형, String, enum, 애노테이션, Class만 허용된다.
② 괄호() 안에 매개변수를 선언할 수 없다.
③ 예외를 선언할 수 없다.
④ 요소를 타입 매개변수로 정의할 수 없다.

  • 아래의 예시를 참고 하자.
@interface AnnTest {
    int id = 100;                    // OK. 상수 선언. static final int id = 100;
    String major(int i, int j);      // 에러. 매개변수를 선언할 수 없음
    String minor() Throws Exception; // 에러. 예외를 선언할 수 없음
    ArrayList<T> list();             // 에러. 요소의 타입에 타입 매개변수 사용 불가
}
profile
나상원의 LOG

0개의 댓글