티스토리 뷰
애너테이션
- 주석처럼 프로그래밍 언어에 영향을 미치지 않으며, 유용한 정보를 제공
- 애너테이션의 사용예
주석처럼 프로그래밍 언어에 영향을 미치지 않으며, 유용한 정보를 제공


애너테이션의 사용예
@Test - JUnit 단위 테스트 프로그램에 유용한 정보 제공하기 위한 것
@Test // 이 메서드가 테스트 대상임을 테스트 프로그램에게 알린다.
public void method() {
...
}
표준 애너테이션
- Java에서 제공하는 애너테이션
- 메타애너테이션 : 애너테이션을 만들 때 사용
Java에서 제공하는 애너테이션
- 메타애너테이션 : 애너테이션을 만들 때 사용ㅈ

@Override
- 오버라이딩을 올바르게 했는지 컴파일러가 체크하게 한다.
- 오버라이딩할 때 메서드이름을 잘못적는 실수를 하는 경우가 많다.
- 오버라이딩할 때는 메서드 선언부 앞에 @Override를 붙이자.
오버라이딩을 올바르게 했는지 컴파일러가 체크하게 한다.
오버라이딩할 때 메서드이름을 잘못적는 실수를 하는 경우가 많다.
오버라이딩할 때는 메서드 선언부 앞에 @Override를 붙이자.
예제12-7
@Override를 주석처리하면, 에러가 잡히지 않는다.
class Parent {
void parentMethod() { }
}
class Child extends Parent {
// @Override
void parentmethod() { } // 조상 메서드의 이름을 잘못 적었음.
}
Problem Description | Method does not override method from its superclass
해석 : 이 메서드(parentmethod)는 조상의 메서드를 오버라이딩하지 않았다.
@Deprecated
- 앞으로 사용하지 않을 것을 권장하는 필드나 메서드에 붙인다.
- @Deprecated의 사용 예, Date클래스의 getDate()
- @Deprecated가 붙은 대상이 사용된 코드를 컴파일하면 나타나는 메시지
@Deprecated의 사용 예, Date클래스의 getDate()
@Deprecated
public int getDate() {
return normalize().getDayOfMonth();
}
삭제하지 않고 이렇게 처리하는 이유는 Java가 '하위 호환성'을 고려하기 때문이다.

@Deprecated가 붙은 대상이 사용된 코드를 컴파일하면 나타나는 메시지
- @Deprecated된 필드나 메서는 에러가 아니다.

예제12-7-2
IDE 환경에서는 자동으로 컴파일을 해주기 때문에, 아까 같은 메시지가 있는지 없는지 모른다. 따라서 터미널 환경에서 직접 파일을 실행해보자.
jiwoo@Jiwooui-MacBookPro ~/java_basic/java_basic/src/ch12 main ±✚ javac Ex12_7_2.java
Ex12_7_2.java
Note: Ex12_7_2.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
2 errors
위에서 배웠던 메세지가 그대로 나왔다. -Xlint:deprecation이라는 옵션을 주고 다시 컴파일해보자(javac).
~/java_basic/java_basic/src/ch12 javac -Xlint:deprecation Ex12_7_2.java
Ex12_7_2.java:16: warning: [deprecation] parentMethod() in Child2 has been deprecated
c.parentMethod(); // deprecated된 메서드 사용
^
1 warning
경고(warning)에 대한 세부내용이 출력된다.
@FunctionalInterface
- 함수형 인터페이스에 붙이면, 컴파일러가 올바르게 작성했는지 체크
- 함수형 인터페이스에는 하나의 추상메서드만 가져야 한다는 제약이 있음
함수형 인터페이스에 붙이면, 컴파일러가 올바르게 작성했는지 체크
함수형 인터페이스에는 하나의 추상메서드만 가져야 한다는 제약이 있음
- 안 붙여도 에러가 나지는 않는다.
- 함수 인터페이스라는 것을 알려주는 효과도 있다.
- 추상 메서드가 하나 있다.(run())
@FunctionalInterface
public interface Runnable {
public abstract void run(); // 추상 메서드
}
| 참고 | '함수형 인터페이스'는 14장에서 배운다.
예제12-7-2
Warning | Multiple non-overriding abstract methods found in interface ch12.Testable
해석 : 두 개 이상의 오버라이딩되지 않은 추상 메서드가 Testable인터페이스에서 발견되었다.
@FunctionalInterface
interface Testable { // 함수형 인터페이스는 하나의 추상메서드만 가능
void test(); // 추상메서드
void check(); // 추상메서드
}
함수형 인터페이스에는 하나의 추상메서드만 가져야 한다는 제약이 있기 때문에, 이러한 경고 메세지가 컴파일러에 의해 출력된다.
@SuppressWarnings
- 컴파일러의 경고메시지가 나타나지 않게 억제한다.
- 괄호()안에 억제하고자 하는 경고의 종류를 문자열로 지정.
- 둘 이상의 경고를 동시에 억제하려면 다음과 같이 한다.
- '-Xlint'옵션으로 컴파일하면, 경고메시지를 확인할 수 있다. 괄호[] 안의 경고의 종류. 아래의 경우 rawtypes
괄호()안에 억제하고자 하는 경고의 종류를 문자열로 지정
@SuppressWarnings("unchecked"). // 지네릭스와 관련된 경고를 억제
ArrayList list = new ArrayList(); // 지네릭 타입을 지정하지 않았음.
list.add(obj); // 여기에서 경고가 발생
@SuppressWarnings 애너테이션을 붙인 것은 컴파일러가 알려준 경고를 확인했다는 표시이다.
둘 이상의 경고를 동시에 억제하려면 다음과 같이 한다.
@SuppressWarnings({"deprecation", "unchecked", "varargs"});
'-Xlint'옵션으로 컴파일하면, 경고메시지를 확인할 수 있다. 괄호[] 안의 경고의 종류. 아래의 경우 rawtypes
~/java_basic/java_basic/src/ch12 javac -Xlint:deprecation Ex12_7_2.java
Ex12_7_2.java:16: warning: [deprecation] parentMethod() in Child2 has been deprecated
c.parentMethod(); // deprecated된 메서드 사용
^
1 warning
예제12-7-2
~/java_basic/java_basic/src/ch12 javac -Xlint:deprecation Ex12_7_2.java
Ex12_7_2.java:16: warning: [deprecation] parentMethod() in Child2 has been deprecated
c.parentMethod(); // deprecated된 메서드 사용
^
1 warning
위 처럼 메세지가 안 나오게 하려면 호출하는 메서드(main메서드)에 @SuppressWarnings("deprecation") 애너테이션을 사용하면 된다.
IDE가 아닌 터미널 환경에서 다시 소스파일을 컴파일해보자.
~/java_basic/java_basic/src/ch12 javac -Xlint:deprecation Ex12_7_2.java
메세지가 나오지 않는 것을 확인할 수 있다.
~/java_basic/java_basic/src/ch12 javac -Xlint:deprecation Ex12_7_2.java
메타 애너테이션
- 메타 애너테이션은 '애너테이션을 위한 애너테이션'
- java.lang.annotation패키지에 포함
메타 애너테이션은 '애너테이션을 위한 애너테이션'
java.lang.annotation패키지에 포함

@Target
- 애너테이션을 정의할 때, 적용대상 지정에 사용
애너테이션을 정의할 때, 적용대상 지정에 사용
@Retention
- 애너테이션이 유지(retention)되는 기간을 지정하는데 사용
- 컴파일러에 의해 사용되는 애너테이션의 유지 정책은 SOURCE이다.
- 실행시에 사용 가능한 애너테이션의 정책은 RUNTIME이다.
애너테이션이 유지(retention)되는 기간을 지정하는데 사용
컴파일러에 의해 사용되는 애너테이션의 유지 정책은 SOURCE이다.
실행 시에 사용 가능한 애너테이션의 정책은 RUNTIME이다.
(참고)@Documented
- javadoc으로 작성한 문서에 포함시키려면 @Documented를 붙인다.
(참고)@Inherited
- 애너테이션을 자손 클래스에 상속하고자 할 때, @Inherited를 붙인다.
(참고)@Repeatable
- 반복해서 붙일 수 있는 애너테이션을 정의할 때 사용
- @Repeatable이 붙은 애너테이션은 반복해서 붙일 수 있다.
- @Repeatable인 @ToDo를 하나로 묶을 컨테이너 애너테이션도 정의해야 함
애너테이션 타입 정의하기
- 애너테이션을 직접 만들어 쓸 수 있다.
- 애너테이션의 메서드는 추상 메서드이며, 애너테이션을 적용할 때 지정(순서X)
애너테이션을 직접 만들어 쓸 수 있다.
@interface 애너테이션이름 {
타입 요소이름(); // 애너테이션의 요소를 선언한다.
}
@interface DateTime {
String yymmdd(); // 날짜
String hhmmss(); // 시간
}
DateTime이라는 애너테이션은 두 개의 요소를 가지고 있다. 두 요소 모두 '추상메서드'이다.
애너테이션의 메서드는 추상 메서드이며, 애너테이션을 적용할 때 지정(순서X)
@interface TestInfo {
int count();
String testedBy();
String[] testTools();
TestType testType(); // enum TestType { FIRST, FINAL }
DateTime testDate(); // 자신이 아닌 다른 애너테이션(@DateTime)을 포함할 수 있다.
}
TestInfo애너테이션을 만들었다. 이제 TestInfo애너테이션을 사용해보자.
@TestInfo {
count=3, testedBy="kim",
testTools={"JUnit", "AutoTester"},
testType=TestType.FIRST,
testDate=@DateTime(yymmdd="160101", hhmmss="235959")
}
public class NewClass { ... }
anno.count() = 3;이 나온다. 우리는 호출보다는 사용하는 경우가 훨씬 많다.
애너테이션의 요소
- 적용 시 값을 지정하지 않으면, 사용될 수 있는 기본값 지정 가능(null제외)
- 요소가 하나이고 이름이 value일 때는 요소의 이름이 생략가능
- 요소의 타입이 배열인 경우, 괄호{}를 사용해야 한다.
적용 시 값을 지정하지 않으면, 사용될 수 있는 기본값 지정 가능(null제외)
@interface TestInfo {
int count() default 1; // 기본값을 1로 지정
}
@TestInfo // @TestInfo(count=1)과 동일
public class NewClass { ... }
요소가 하나이고 이름이 value일 때는 요소의 이름이 생략가능
@interface TestInfo {
String value();
}
@TestInfo("passes") // @TestInfo(value="passed")와 동일
class NewClass { ... }
| 참고 | 요소의 이름이 별루(value)일 떄는 생략 가능하다고 생각하시면 외우기 쉽습니다.
요소의 타입이 배열인 경우, 괄호{}를 사용해야 한다.
@interface TestInfo {
String[] testTools();
}
@Test(testTools={"JUnit", "AutoTester"})
@Test(testTools="JUnit")
@Test(testTools={}) // 값이 없을 때는 괄호{}가 반드시 필요
모든 애너테이션의 조상 - java.lang.annotation.Annotation
- Annotation은 모든 애너테이션의 조상이지만 상속은 불가
- 사실 Annotation은 인터페이스이다.
Annotation은 모든 애너테이션의 조상이지만 상속은 불가
@interface TestInfo extends Annotation { // 에러. 허용되지 않는 표현
int count();
String testedBy();
...
}
사실 Annotation은 인터페이스이다.
- 추상메서드 구현하지 않고, 사용 가능
package java.lang.annotation;
public interface Annotation { // Annotation자신은 인터페이스이다.
boolean equals(Object obj);
int hashCode(); // 추상메서드 - 구현x but 사용 가능
String toString(); // 추상메서드 - 구현x but 사용 가능
Class<? extends Annotation> annotationType(); // 애너테이션의 타입을 반환
}
마커 애너테이션 - Marker Annotation
- 요소가 하나도 정의되지 않은 애너테이션
요소가 하나도 정의되지 않은 애너테이션
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {} // 마커 애너테이션. 정의된 요소가 하나도 없다.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Test {} // 마커 애너테이션. 정의된 요소가 하나도 없다.
@Test // 이 메서드가 테스트 대상임을 테스트 프로그램에게 알린다.
public void method() {
...
}
@Deprecated
public int getDate() {
return normalize().getDayOfMonth();
}
애너테이션 요소의 규칙
- 애너테이션의 요소를 선언할 때 아래의 규칙을 반드시 지켜야 한다.
- 아래의 코드에서 잘못된 부분은 무엇인지 생각해보자.
애너테이션의 요소를 선언할 때 아래의 규칙을 반드시 지켜야 한다.
- 요소의 타입은 기본형, String, enum, 애너테이션, Class만 허용됨
- 괄호()안에 매개변수를 선언할 수 없다.
- 예외를 선언할 수 없다.
- 요소를 타입 매개변수로 정의할 수 없다.
아래의 코드에서 잘못된 부분은 무엇인지 생각해보자.
@interface AnnoTest {
int id = 100;
String major(int i, int j);
String minor() throws Exception;
ArrayList<T> list();
}
int id = 100;
상수 OK(static final 생략), default메서드 X
String major(int i, int j);
에러. 괄호()안에 매개변수를 선언할 수 없다.
String minor() throws Exception;
에러. 예외를 선언할 수 없다.
ArrayList<T> list();
에러. 요소를 타입 매개변수로 정의할 수 없다.
예제12-8
'Java의 정석_기초편' 카테고리의 다른 글
| 쓰레드(thread) (0) | 2022.11.10 |
|---|---|
| 열거형 (0) | 2022.11.08 |
| 지네릭 타입의 형 변환 (0) | 2022.11.08 |
| 와일드카드 & 지네릭 메서드 (0) | 2022.11.08 |
| 제한된 지네릭 클래스 & 지네릭스의 제약 (0) | 2022.11.08 |
