어노테이션
어노테이션은 Java5에 추가된 기능
어노테이션
개념
- ‘주석’이라는 의미를 가짐
- 소스코드에 메타코드(추가정보)를 주는 것
문법
- 클래스나 메소드 위에 붙여 사용
- @(at)기호로 이름이 시작 (예: @Override)
용도
- 컴파일러에게 코드 작성 문법 에러를 체크하도록 정보를 제공
- 소프트웨어 개발툴이 빌드나 배치시 코드를 자동으로 생성할 수 있도록 정보 제공
- 실행시(런타임시) 특정 기능을 실행하도록 정보를 제공
- 어노테이션을 클래스나 메타코드에 붙인 후, 클래스가 컴파일되거나 실행될 때 어노테이션의 유무나 어노테이션에 설정된 값을 통하여 클래스가 좀 더 다르게 실행되게 할 수 있음
- 이런 이유로 어노테이션을 일정의 설정파일처럼 설명하는 경우도 있음
종류
- 내장(표준) 어노테이션: Java가 기본으로 제공하는 어노테이션
- 커스텀(Custom) 어노테이션:사용자가 직접 작성하는 어노테이션
내장(표준) 어노테이션
- 7개의 표준 어노테이션 중에 3개가 java.lang의 일부이며, 나머지 4개는 java.lang.annotation으로부터 가져옴
종류
자바 코드에 적용되는 내장 어노테이션
- @Override
- 선언한 메서드가 오버라이드 되었다는 것을 나타냄
- 만약 상위(부모) 클래스(또는 인터페이스)에서 해당 메소드를 찾을 수 없다면 컴파일 에러를 발생시킴
- @Deprecated
- 해당 메소드가 더 이상 사용되지 않음을 표시
- 만약 사용할 경우 컴파일 경고를 발생시킴
- @SuppressWarnings
- 선언한 곳의 컴파일 경고를 무시
- @SafeVarargs
- Java7 부터 지원하며, 제너릭 같은 가변인자의 매개변수를 사용할 때의 경고를 무시
- @FunctionalInterface
- Java 8부터 지원하며, 함수형 인터페이스를 지정하는 어노테이션
- 만약 메소드가 존재하지 않거나, 1개 이상의 메소드(default 메소드 제외)가 존재할 경우 컴파일 오류를 발생시킴
기타 어노테이션에 적용되는 어노테이션 (메타 애터네이션)
- @Retention
- Java 컴파일러가 어노테이션을 다루는 방법을 기술하며, 특정 시점까지 영향을 미치는지를 결정
- 종류
- RetentionPolicy.SOURCE: 컴파일 전까지만 유효 (컴파일 이후에는 사라짐)
- RetentionPolicy.CLASS: 컴파일러가 클래스를 참조할 때까지 유효
- RetentionPolicy.RUNTIME: 컴파일 이후에도 JVM에 의해 계속 참조가 가능 (리플렉션 사용)
- @Documented
- 해당 어노테이션을 Javadoc에 포함시킴
- @Target
- 어노테이션이 적용할 위치를 선택
- 종류
- ElementType.PACKAGE: 패키지 선언
- ElementType.TYPE: 타입 선언
- ElementType.ANNOTATION_TYPE: 어노테이션 타입 선언
- ElementType.CONSTRUCTOR: 생성자 선언
- ElementType.FIELD: 멤버 변수 선언
- ElementType.LOCAL_VARIABL: 지역 변수 선언
- ElementType.METHOD: 메서드 선언
- ElementType.PARAMETER: 전달인자 선언
- ElementType.TYPE_PARAMETER: 전달인자 타입 선언
- ElementType.TYPE_USE: 타입 선언
- @Inherited
- 어노테이션의 상속을 가능하게 함
- @Repeatable
- Java 8부터 지원하며, 연속적으로 어노테이션을 선언할 수 있게 해줌
커스텀 어노테이션
- 개념: 사용자가 직접 작성하는 어노테이션
- 이용 방법
- 어노테이션을 정의
- 어노테이션을 클래스에서 사용 (타겟에 적용)
- 어노테이션을 이용해 실행
커스텀 어노테이션 예시
1. 어노테이션 정의
- Package Explorer에서 [new - Annotation]을 이용하여 Count100이라는 어노테이션 생성
- 인터페이스와 비슷한 모양 But, 인터페이스 앞에 @가 붙어있음
- Count100 어노테이션을 JVM 실행 시에 감지할 수 있게 하려면 Count100 어노테이션 위에 @Retention(RetentionPolicy.RUNTIME)를 붙여줘야 함
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Count100 {
}
2. 어노테이션을 클래스에 사용
- "hello"를 출력하는 hello( )메소드를 가지는 MyHello라는 클래스를 작성
- hello메소드 위에 @Count100 어노테이션을 붙임
public class MyHello {
@Count100
public void hello(){
System.out.println("hello");
}
}
3. 어노테이션을 이용해 실행
- MyHello클래스를 이용하는 MyHelloExam클래스를 작성
- MyHello의 hello메소드가 @Count100어노테이션이 설정되어 있을 경우, hello( )메소드를 100번 호출하도록 함
1) MyHello의 객체 생성
MyHello hello = new MyHello();
2) 메소드에 대한 정보를 얻어낼 수 있는 코드를 작성
- MyHello 클래스의 hello( )메소드 정보를 알아내기 위해 메소드 타입으로 객체 생성 > method는 hello( )메소드에 대한 정보를 갖게 됨
- Method는 java.lang.reflect.Method 클래스임
- getClass( )메소드
- java.object가 갖고 있는 메소드
- 해당 인스턴스를 만들 때 사용한 클래스의 정보를 리턴
- getDeclaredMethod( )메소드
- 해당 클래스에 대한 정보를 얻고 그 정보로부터 hello라는 이름의 메소드에 대한 정보를 리턴
Method method = hello.getClass().getDeclaredMethod("hello");
3) getDeclaredMethod( )메소드는 Exception 처리를 해야 함
-
catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); }
- 자동완성으로 try-catch문을 작성하면 예외가 2개 작성되지만, NoSuchMethodException과 SecurityException는 Exception을 상속받기 때문에 Exception 하나로 처리할 수 있음
MyHello hello = new MyHello();
try{
Method method = hello.getClass().getDeclaredMethod("hello");}
}catch(Exception e){
ex.printStackTrace();
}
4) try문 안에 hello( )메소드를 100번 호출하는 if문 작성
- MyHello의 Hello( )메소드에 Count100 어노테이션이 적용되어 있다면 for문으로 이동해, MyHello의 Hello( )메소드가 100번 실행됨
- 적용되어 있지 않다면 else문으로 이동해, MyHello의 Hello( )메소드가 딱 한 번만 실행됨
- method가 가지고 있는 isAnnotationPresent( )메소드
- 특정 어노테이션이 메소드에 적용되어 있는지를 boolean 타입으로 리턴
- Class에서 호출했을 때 부모클래스에 적용된 경우도 true를 리턴
if(method.isAnnotationPresent(Count100.class)){
for(int i = 0; i < 100; i++){
hello.hello();
}
}else{
hello.hello();
}
완성 코드
import java.lang.reflect.Method;
public class MyHelloExam {
public static void main(String[] args) {
MyHello hello = new MyHello();
try{
Method method = hello.getClass().getDeclaredMethod("hello");
if(method.isAnnotationPresent(Count100.class)){
for(int i = 0; i < 100; i++){
hello.hello();
}
}else{
hello.hello();
}
}catch(Exception e){
ex.printStackTrace();
}
}
}
실습
- 문제 설명
- 어노테이션은 메소드가 특정한 방식으로 동작하도록 표시하는데 쓸 수 있는데요. @RunTwice 어노테이션을 AnnotationExam의 원하는 메소드에 붙여보고 [제출]을 눌러보세요. 해당 메소드가 두 번 실행되는 걸 확인할 수 있습니다.
- 해설
- 메소드1~3 중 원하는 메소드 위에 @RunTwice 어노테이션을 붙이면 해당 메소드가 2번 호출됨
- 1. 어노테이션을 정의
- 어노테이션을 JVM실행시에 감지할 수 있도록 하려면 @Retention(RetentionPolicy.RUNTIME)를 붙여줘야 합니다.
- 2. 어노테이션을 클래스에서 사용
- 타겟 메소드 위에 @RunTwice 어노테이션을 붙힙니다.
- 3. 어노테이션을 이용하여 실행
- AnnotationExam의 타겟 메소드가 @RunTwice어노테이션이 설정되어 있을 경우, 타겟 메소드를 2번 호출하도록 합니다.
- RunTwice 어노테이션 클래스
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface RunTwice{
}
- AnnotationExam 클래스
import java.lang.reflect.Method;
public class AnnotationExam{
//메소드1~3 중 원하는 부분에 @RunTwice 어노테이션을 붙여보세요.
@RunTwice
public void method1(){
System.out.println("메소드 1 입니다.");
}
public void method2(){
System.out.println("메소드 2 입니다.");
}
public void method3(){
System.out.println("메소드 3 입니다.");
}
public static void main(String[] args){
AnnotationExam exam = new AnnotationExam();
try {
Method method = exam.getClass().getDeclaredMethod("method1");
if(method.isAnnotationPresent(RunTwice.class)){
exam.method1();exam.method1();
}
method = exam.getClass().getDeclaredMethod("method2");
if(method.isAnnotationPresent(RunTwice.class)){
exam.method2();exam.method2();
}
method = exam.getClass().getDeclaredMethod("method3");
if(method.isAnnotationPresent(RunTwice.class)){
exam.method3();exam.method3();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
'☕ Java 웹 프로그래밍 > Java' 카테고리의 다른 글
[프로그래머스] Java(자바) 중급 | Part 8. 람다(Lambda) (2) | 2023.05.19 |
---|---|
[프로그래머스] Java(자바) 중급 | Part 7. 스레드 (0) | 2023.05.18 |
[프로그래머스] Java(자바) 중급 | Part 5. IO (0) | 2023.05.15 |
[프로그래머스] Java(자바) 중급 | Part 4. 날짜와 시간 (2) | 2023.05.13 |
[프로그래머스] Java(자바) 중급 | Part 3. java.util 패키지 (0) | 2023.05.13 |