자바(Java)

[자바] 자바 어노테이션

Ash_jisu 2023. 10. 5. 11:56

어노테이션

어노테이션이란?

어노테이션은 자바 1.5부터 추가된 요소로 사전적 의미로는 주석을 의미한다. 하지만 자바에서는 단순 주석이 아닌 클래스에 특수한 의미를 부여하거나 기능을 주입하기 위한 메타데이터라고 볼 수 있다. 어노테이션은 인터페이스 일종으로 @를 사용하여 선언한다. 전에  JUNIT 테스트시 사용하는 @Test도 어노테이션이다. 단지 이게 테스트해야한다는 것을 프로그램에게 알리는 역할을 할 뿐, 메서드가 포함된 프로그램에는 아무런 영향을 미치지 않는다. 

 

 

어노테이션의 용도

  • 컴파일러에게 코드 문법 에러를 체크하도록 정보를 제공
  • 인텔리제이 같은 소프트웨어 개발 툴이 빌드나 배치 시 코드를 자동으로 생성할 수 있도록 정보를 제공
  • 런타임 시 특정기능을 실행하도록 정보를 제공

 

어노테이션의 종류

  • Built-in Annotation: 자바에서 기본으로 제공하는 어노테이션
  • Meta Annotation: 커스텀 어노테이션을 만들 수 있게 제공된 어노테이션

 

어노테이션 정의

커스텀 어노테이션을 만들려면 @interface [생성할 어노테이션 이름] 의 형태로 어노테이션을 정의해야한다. 어노테이션을 정의할 때, 생성되는 어노테이션에 대한 메타 어노테이션은 어노테이션 정의 앞쪽에 붙여준다.

 

예시

MyAnnotation

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "MyAnnotation : default value";
}

 

MyObject

public class MyObject {
    @MyAnnotation
    public void testMethod1() {
        System.out.println("This is testMethod1");
    }

    @MyAnnotation(value = "Custom Value")
    public void testMethod2() {
        System.out.println("This is testMethod2");
    }
}

 

Main

public class Main {
    public static void main(String[] args) {
        //리플렉션을 사용하여 MyObject 클래스의 메서드 정보를 가져온다
        Method[] methodList = MyObject.class.getMethods();

        for (Method method : methodList) {
            if(method.isAnnotationPresent(MyAnnotation.class)) {
                MyAnnotation annotation=method.getDeclaredAnnotation(MyAnnotation.class);
                String value=annotation.value();
                System.out.println(method.getName() + ":" + value);
            }
        }
    }
}

출력 결과

 

 


Built-in Annotation

기본으로 제공되는 어노테이션

종류
설명
@Override
컴파일러에게 오버라이딩하는 메서드라는 것을 알린다
@Deprecated
앞으로 사용하지 않을 것을 권장하는 대상에 붙인다
@SuppressWarnings
컴파일러 특정 경고메시지가 나타나지 않게 해준다 
@SafeVarargs
자바 1.7이상부터 사용가능하며 제네릭스 타입의 가변인자에 사용한다
@FunctionalInterface
자바 1.8이상부터 사용가능하며 함수형 인터페이스 라는 것을 알린다

출처: 자바의 정석

 

Override

  • 메서드 앞에만 붙일 수 있는 에너테이션, 조상의 메서드를 오버라이딩하는 것이라는 걸 컴파일러에게 알려주는 역할을 함
  • 이제 상속받은 자식 클래스에서 메서드를 잘못 적어도 컴파일러는 그저 새로운 이름의 메서드가 추가 된지알음 → Override어노테이션을 통해 컴파일러부모에 이 메서드가 존재하는지 유무를 파악함 (한마디로 실수방지)

 

 Deprecated

  • 새로운 버전의 JDK가 소개될때, 안쓰거나 대체된 기능들이 존재하는데 그러한 필드나 메서드에 Deprecated어노테이션을 붙여 다른 대상으로 대체되거나 더 이상 사용되지않는 다는것을 의미한다.
  • 사용해도 문제는 없다(권장일뿐 강제성은 없기때문이다)
  • 관련해서 Deprecated 메서드들 정리되어있는글 한번 보기
  • 예시
    • 전에 쓰레드 공부할때 suspend, destroy, resum, stop 메서드가 더이상 사용하지 않는 메서드여서 어노테이션으로 명시되어있다

 

FunctionalInterface

  • 함수형 인터페이스 선언시 사용, 컴파일러가 함수형 인터페이스를 올바르게 선언했는지 확인, 잘못된 경우 에러 발생
  • 따라서 함수형 인터페이스를 선언할대 꼭 붙여주자

    ※함수형 인터페이스
    • 5가지가 존재한다
      • Consumer
      • Supplier
      • Function
      • Operator
      • Predicated

 

 

SuppressWarnings

  • 컴파일러가 보여주는 경고메시지가 나타나지 않게 억제해준다, 한마디로 경고가 발생할 것을 알면서도 묵인해야할때 사용한다
  • 주로 사용되는 것은 “deprecation”, “unchecked”, “rawtypes”, “varags”정도가 있다

경고 사용되는 예시

public class Main {
    public static void main(String args[]){
        Thread th = new Thread();
        th.start();
        th.run();
        th.stop();
    }
}
경고 발생
public class Main {
    @SuppressWarnings("deprecation")
    public static void main(String args[]){
        Thread th = new Thread();
        th.start();
        th.run();
        th.stop();
    }
}

추가하면 경고가 없어진것을 확인 할 수 있다.

 

 

Safe Varags

이것을 알기전에 하나 알고가야한다, 추가로 이 애너테이션은 static 이나 final이 붙은 메서드와 생성자에만 붙일 수 있음

  • Reifiable Type
    Java에서 Runtime시에 완전하게 오브젝트 정보를 표현할 수 있는 타입을 가르켜 Reifiable 하다고 합니다.Reifiable 가능한 타입 정보는 다음과 같습니다.
    1. 원시 타입(int, double, float, byte 등등)
    2. Number, Integer와 같은 일반 클래스와 인터페이스 타입
    3. Unbounded Wildcard가 포함된 Parameterized Type(List<?>, ArrayList<?> 등)
    4. Raw Type(List, ArrayList, Map 등)
    • 이제 메서드에 선언된 가변자의 타입이 non-reifiable타입의 경우, 한마디로 컴파일시에 정보가 제거된 유형이다.
    public class Main {
        public static <T> void myMethod(T... args) { //제너릭 사용
    
        }
        public static void main(String[] args) {
            List<String> myList = new ArrayList<>();
            // 경고 발생: non-reifiable 타입인 제네릭 배열을 가변인자로 전달
            myMethod(myList.toArray(new String[0]));
        }
    }
    ​
경고 발생

 해결법

public class Main {
    @SafeVarargs
    public static <T> void myMethod(T... args) { //제너릭 사용

    }
    public static void main(String[] args) {
        List<String> myList = new ArrayList<>();
        // 경고 발생: non-reifiable 타입인 제네릭 배열을 인자로 전달
        myMethod(myList.toArray(new String[0]));
    }
}

 

 

 

 


Meta Annotation

정확한 의미는 어노테이션을 위한 에너테이션, 즉 어노테이션  붙이는 어노테이션으로  어노테이션 을 정의할때 어노테이션 의 적용대상이나 유지기간등을 지정하는데 사용된다.
간략하게 말하면 커스텀 어노테이션을 만들 수 있게 제공된 어노테이션이다

종류
설명
@Retention
어노테이션이 유지되는 범위를 지정하는데 사용된다
@Documented
어노테이션 정보를 javadoc으로 작성된 문서에 포함되게 한다
@Target
어노테이션이 적용할 위치를 지정합니다. 여러 값일 경우 {} 사용
@Inherited
어노테이션이 자손 클래스에 상속되도록 한다
@Repeatable
자바 1.8이상부터 사용가능하며 에노테이션을 반복해서 적용할 수 있게 한다

출처: 자바의 정석

 

 

Retention

  • 에너테이션이 유지되는 기간 지정하는데 사용
  • 세가지 유지정책
    • RetentionPolicy.Source: 컴파일 전까지만 유효
    • RetentionPolicy.CLASS: 컴파일러가 클래스를 참조할 때까지 유효
    • RetentionPolicy.RUNTIME: 컴파일 이후에도 JVM에 의해 계속 참조 가능

Built-in Annotation중 하나인 Deprecated의 자바 문서를 보면 컴파일 이후에도 계속 참조가능하도록 RUNTIME으로 유지정책이 되어있는것을 볼 수 있다

 

 

 

Target

Target은 어노테이션이 적용될 위치를 지정하는 어노테이션이다.

 

종류

  • ElementType.PACKAGE: 패키지선언
  • ElementType.TYPE: 타입선언
  • ElementType.ANNOTATION_TYPE: 어노테이션 타입
  • ElementType.CONSRTUCTOR:  생성자 선언
  • ElementType.FIELD: 멤버 변수 선언
  • ElementType.LOCAL_VARIABLE: 지역 변수 선언
  • ElementType.METHOD: 메서드 선언 
  • ElementType.PARAMETER: 전달인자 선언
  • ElementType.TYPE_PARAMETER: 전달인자 타입 선언
  • ElementType.TYPE_USE: 타입선언

아래 예시처럼 적용될 위치를 설정해주면 된다

@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "MyAnnotation : default value";
}

 

 

 

 

 

 Documented

  • 해당 어노테이션을 javadoc 파일에 추가시킬지 여부이다.
/**
 * MyAnnotation
 * add javadoc for helping to explain documented
 * 
 */

@Documented
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "MyAnnotation : default value";
}

위와 같이 Documented 출력하고 인텔리제이에서 Tools -> Generated javadoc 하게되면 
아래와 같이 공식 문서처럼 출력된다

 

 

 

생성 과정 관련해서는 아래 블로그를 참고하면 편하다

https://babgeuleus.tistory.com/105

 


어노테이션 프로세서

  • 어노테이션 프로세스는 Java 소스 코드 및 클래스 파일에서 어노테이션 정보를 추출하고 이를 활용하여 추가 작업을 수행하는 자동화된 프로세스입니다. 
  • 컴파일 시간에 실행되며, 컴파일러가 소스 코드를 처리하는 동안 어노테이션 정보를 검사한다.
  • 주로 코드 생성, 코드 검증, 설정 파일 생성 및 기타 자동화 작업을 수행하는데 사용된다.
  • 예시로는 Override와 Lombok 라이브러리 등이 있다.

 

아래 링크로 들어가면 더 자세한 설명과 함께  특정  Annotation을 사용하는 클래스는 변경할 때마다 그대로 적용이 되어 Maven Compile을 안하도록 설정하는 상세한 방법이 나와있다. -> 예시로 따로 소스코드에 getter 및 setter함수를  개발자가 직접 만들지 않고 setName, getName등의 함수를 쓸 수 있다

https://roadj.tistory.com/9

 

어노테이션 프로세스를 통해 메타프로그래밍 기법을 활용하여 보다 유연하고 효율적인 소프트웨어 개발이 가능해진다

 

 

 

 


출처

자바의 정석(저자:남궁성)

 

https://blog.naver.com/swoh1227/222229853664

 

https://roadj.tistory.com/9