[JAVA] 애너테이션

DANI·2023년 12월 13일
0

JAVA를 공부해보자

목록 보기
22/29
post-thumbnail

📕 1. 애너테이션 이란?

  • 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것.
  • 주석, 주해, 메모
@Override
public void method(){
    
}

이 메서드가 재정의 됐음을 알려준다. 메서드 자체에는 영향을 미치지 않음.


🔍 @Override의 API

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

📝 1-1. `메타 애너테이션

  • 애너테이션을 위한 애너테이션
  • 애너테이션을 붙이는 애너테이션으로 애너테이션을 정의할 때 애너테이션의 적용대상(target)이나 유지기간(retention)등을 지정하는데 사용된다.
  • 메타 애너테이션은 "java.lang.annotation" 패키지에 포함되어 있다.

@Target(ElementType.METHOD) -> 타겟이 Enum상수로 정의되어 있다. 적용대상을 나타냄
@Retention(RetentionPolicy.SOURCE) -> 시점에 대한 애너테이션. 애너테이션이 유지되는 기간

🔍@Retention(RetentionPolicy.SOURCE)의 API

public enum RetentionPolicy {

    SOURCE, //  소스 파일에만 존재, 클래스 파일 존재X -> 컴파일 시점에 정보가 전달됨, 컴파일 이후에 제거
    CLASS, // 자바코드에 존재(java), 클래스 파일에 존재(class) -> 디폴트값, 정보전달X(거의 사용X)
    RUNTIME // 자바코드에 존재(java), 클래스 파일에 존재(class) -> 실행 중에 정보가 전달(많이 사용)
}

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


📝 1-2. 표준 애너테이션

  • 메서드 앞에만 붙일 수 있는 에너테이션
  • 상위클래스의 메서드를 재정의 하는 것이라는 걸 컴파일러에게 알려주는 역할을 한다.
  • 재정의할 떄 메서드 앞에 '@Override'라고 애너테이션을 붙이면, 컴파일러가 같은 이름의 메서드가 상위 클래스에 있는지 확인하고 없으면 에러메세지를 출력한다.
  • 재정의할 때 메서드 앞에 '@Override'를 붙이는 것이 필수는 아니지만 알아내기 어려운 실수를 미연에 방지해 주므로 붙이는 것이 좋다.

  1. @Deprecated : 다른 것으로 대체되었으니 더 이상 사용하지 않을 것을 권한다는 의미
  2. @FunctionalInterface : '함수형 인터페이스(functional interface)'를 선언할 때, 이 애너테이션을 붙이면 컴파일러가 '함수형 인터페이스'를 올바르게 선언했는지 확인하고, 잘못된 경우 에러를 발생
  3. @SupressWarnings : 컴파일러가 보여주는 경고메시지가 나타나지 않게 억제해 준다.
    1) deprecation : "@Deprecated"가 붙은 대상을 사용해서 발생하는 경고를 억제
    2) unchecked : 지네릭스로 타입을 지정하지 않았을 때 발생하는 경고를 억제
    3) rawtypes : 지네릭스를 사용하지 않아서 발생하는 경고를 억제
    4) varargs : 가변인자의 타입이 제네릭 타입일 때 발생하는 경고를 억제

    둘 이상의 경고를 억제할 땐 배열로 정의 @SupressWarnings({...})

  4. @SafeVarags
    메서드에 선언된 가변인자의 타입이 non-reifiable타입일 경우,

    해당 메서드를 선언하는 부분과 호출하는 부분에서 "unchecked"경고가 발생한다

    해당 코드에 문제가 없다면 이 경고를 억제하기 위해 "@SafeVarargs"를 사용해야 한다.

이 애너테이션은 static이나 final이 붙은 메서드에만 붙일 수 있다. 즉 오버라이드 될 수 있는 메서드에는 사용할 수 없다.


💡 non-reifiable 타입 이란?

지네릭스에서 살펴본 것과 같이 어떤 타입들은 컴파일 이후에 제거된다.
컴파일 후에도 제거되지 않는 타입을 reifiable타입이라 하고, 제거되는 타입을 non-reifiable타입이라고 한다.
지네릭 타입들은 대부분 컴파일 시에 제거되므로 non-reifiable타입이다.



📝 2. 애너테이션 타입 정의하기


  • 애너테이션 내에 선언된 메서드를 '애너테이션의 요소(element)'라고 한다.
  • 애너테이션에도 인터페이스처엄 상수를 정의할 수 있지만 디폴트 메서드는 정의할 수 없다.
  • 반환값이 있고 매개변수는 없는 추상 메서드의 형태를 가지며, 상속을 통해 구현하지 않아도 된다.
  • 애너테이션의 각 요소는 기본값을 가질 수 있으며, 기본값이 있는 요소는 애너테이션을 적용할 때 값을 지정하지 않으면 기본값이 사용된다.

    값을 지정할 필요가 없는 경우, 애너테이션의 요소를 하나도 정의하지 않을 수 있다. Serializable이나 Cloneable인터페이스처럼, 요소가 하나도 정의되지 않은 애너테이션을 마커 애너테이션이라고 한다.



🔴 애너테이션 만들기(@Myannotation)

package annotation;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface Myannotation {
    String value(); // 추가적인 정보 전달 설정가능
}

🔴 애너테이션 만들기(@Myannotation2)

package annotation;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Myannotation2 {
    String value() default "기본값"; // 디폴트값 설정 가능
    int[] nums();

}

🔴 애너테이션 만들기(MyClass)

package annotation;

import java.util.Arrays;

@Myannotation(value = "값")
public class MyClass {

    @Myannotation(value = "값")
    int num;

    @Myannotation(value = "값")
    public int add(int ... num){
        return Arrays.stream(num).sum();
    }
}

🔴 Main 클래스

package annotation;

import java.util.Arrays;

// @Myannotation2(value ="값", nums = {1, 2, 3})
@Myannotation2(nums = {1, 2, 3})
public class Myclass2 {
    public static void main(String[] args) {


        Class cls = Myclass2.class;
        Myannotation2 anno = (Myannotation2) cls.getAnnotation(Myannotation2.class);

        String value = anno.value();
        System.out.println(value);

        int[] nums = anno.nums();
        System.out.println(Arrays.toString(nums));
    }

//    @Myannotation2(nums = {1,2,3})
//    public static int add(int ... a){
//        return Arrays.stream(a).sum();
//    }
}

0개의 댓글