1. 개요

이 기사에서는 JDK에서 사용할 수있는 기본 주석 인 Java 언어의 핵심 기능에 대해 설명합니다.

2. 주석이란?

간단히 말해, 주석은 "@"기호가 앞에 오는 Java 유형입니다 .

Java는 1.5 릴리스 이후로 주석을 달았습니다. 그 이후로 그들은 우리가 응용 프로그램을 설계하는 방식을 형성했습니다.

Spring과 Hibernate는 다양한 디자인 기술을 가능하게하기 위해 주석에 크게 의존하는 프레임 워크의 훌륭한 예입니다.

기본적으로 주석은 바인딩 된 소스 코드에 추가 메타 데이터를 할당합니다 . 메소드, 인터페이스, 클래스 또는 필드에 주석을 추가하여 다음을 수행 할 수 있습니다.

  1. 경고 및 오류에 대해 컴파일러에 알립니다.
  2. 컴파일 타임에 소스 코드 조작
  3. 런타임시 동작 수정 또는 검사

3. 자바 내장 주석

이제 기본 사항을 검토 했으므로 핵심 Java와 함께 제공되는 몇 가지 주석을 살펴 보겠습니다. 첫째, 컴파일을 알리는 몇 가지가 있습니다.

  1. @우세하다
  2. 안녕하세요.
  3. @Deprecated
  4. 뿡 빵뀨
  5. @FunctionalInterface
  6. @원주민

이러한 주석은 컴파일러 경고 및 오류를 생성하거나 억제합니다. 이를 추가하면 향후 프로그래머의 오류를 방지 할 수 있으므로 일관되게 적용하는 것이 좋습니다.

@Override의 주석을 표시하기 위해 사용되는 방법을 대체 또는 대체하는 상속 된 메소드의 동작.

@SuppressWarnings 는 코드의 일부에서 특정 경고를 무시하려고 함을 나타냅니다. @SafeVarargs 주석은 또한 가변 인자를 사용하여 관련 경고의 유형에 역할을합니다.

@Deprecated 어노테이션은 더 이상 사용하기위한 것이 아닙니다 같은 API를 표시하는 데 사용할 수 있습니다. 또한이 주석은 사용 중단에 대한 자세한 정보를 나타 내기 위해 Java 9 에서 개조되었습니다 .

이 모든 것에 대해 링크 된 기사에서 더 자세한 정보를 찾을 수 있습니다.

3.1. @FunctionalInterface

Java 8을 사용하면보다 기능적인 방식으로 코드를 작성할 수 있습니다.

단일 추상 메소드 인터페이스 는 이것의 큰 부분입니다. SAM 인터페이스를 람다에서 사용하려는 경우 선택적으로 @FunctionalInterface 로 표시 할 수 있습니다 .

@FunctionalInterface
public interface Adder {
    int add(int a, int b);
}

메서드가있는 @Override마찬가지로 @FunctionalInterfaceAdder를 사용 하여 우리의 의도를 선언합니다 .

이제 @FunctionalInterface 사용 여부에 관계없이 동일한 방식으로 Adder사용할 수 있습니다 .

Adder adder = (a,b) -> a + b;
int result = adder.add(4,5);

그러나 Adder에 두 번째 메서드를 추가 하면 컴파일러가 다음과 같이 불평합니다.

@FunctionalInterface
public interface Adder { 
    // compiler complains that the interface is not a SAM
    
    int add(int a, int b);
    int div(int a, int b);
}

이제 이것은 @FunctionalInterface 주석 없이 컴파일되었을 것 입니다. 그래서 그것은 우리에게 무엇을 제공합니까?

@Override 와 마찬가지로이 주석은 향후 프로그래머 오류로부터 우리를 보호합니다. 인터페이스에 둘 이상의 메서드가있는 것은 합법적이지만 해당 인터페이스가 람다 대상으로 사용되는 경우는 아닙니다. 이 주석이 없으면 컴파일러는 Adder 가 람다로 사용 된 수십 곳에서 중단됩니다 . 이제 Adder 자체 에서 중단 됩니다.

3.2. @원주민

Java 8 부터는 java.lang.annotation  패키지에 Native 라는  새 주석이  있습니다. @Native  주석 필드에만 적용 할 수 있습니다. 주석이 달린 필드가 네이티브 코드에서 참조 할 수있는 상수임을 나타냅니다 . 예를 들어, Integer  클래스 에서 사용되는 방법은 다음과 같습니다.

public final class Integer {
    @Native public static final int MIN_VALUE = 0x80000000;
    // omitted
}

이 주석은 도구가 일부 보조 헤더 파일을 생성하기위한 힌트로도 사용할 수 있습니다.

4. 메타 주석

다음으로 메타 주석은 다른 주석에 적용 할 수있는 주석입니다.

예를 들어 다음 메타 주석은 주석 구성에 사용됩니다.

  1. @표적
  2. @보유
  3. 상속
  4. @ 문서화
  5. @Repeatable

4.1. @표적

주석의 범위는 요구 사항에 따라 다를 수 있습니다. 하나의 주석은 메서드에만 사용되지만 다른 주석은 생성자 및 필드 선언과 함께 사용할 수 있습니다.

사용자 지정 주석의 대상 요소를 결정하려면 @Target 주석 으로 레이블을 지정해야합니다 .

@Target12 개의 다른 요소 유형 과 함께 작동 할 수 있습니다 . @SafeVarargs 의 소스 코드를 살펴보면 생성자 또는 메서드에만 첨부되어야 함을 알 수 있습니다.

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface SafeVarargs {
}

4.2. @보유

일부 주석은 컴파일러의 힌트로 사용되는 반면 다른 주석은 런타임에 사용됩니다.

@Retention 어노테이션을 사용하여 프로그램 라이프 사이클에서 어노테이션이 적용되는 위치를 지정 합니다.

이렇게하려면 세 가지 보존 정책 중 하나 를 사용하여 @Retention 을 구성해야합니다 .

  1. RetentionPolicy.SOURCE – 컴파일러 나 런타임 모두에서 볼 수 없습니다.
  2. RetentionPolicy.CLASS – 컴파일러에서 볼 수 있습니다.
  3. RetentionPolicy.RUNTIME – 컴파일러 및 런타임에 표시

주석 선언에 @Retention 주석이 없는 경우 보존 정책의 기본값은 RetentionPolicy.CLASS 입니다.

런타임에 액세스 할 수 있어야하는 주석이있는 경우 :

@Retention(RetentionPolicy.RUNTIME)
@Target(TYPE)
public @interface RetentionAnnotation {
}

그런 다음 클래스에 주석을 추가하면 :

@RetentionAnnotation
@Generated("Available only on source code")
public class AnnotatedClass {
}

이제 AnnotatedClass반영하여 얼마나 많은 주석이 유지되는지 확인할 수 있습니다 .

@Test
public void whenAnnotationRetentionPolicyRuntime_shouldAccess() {
    AnnotatedClass anAnnotatedClass = new AnnotatedClass();
    Annotation[] annotations = anAnnotatedClass.getClass().getAnnotations();
    assertThat(annotations.length, is(1));
}

@RetentionAnnotation 에는 RUNTIME 보존 정책이 있지만 @Generated 에는 그렇지 않으므로 값은 1 입니다. 

4.3. 상속

어떤 상황에서는 어노테이션을 부모 클래스에 바인딩하기 위해 서브 클래스가 필요할 수 있습니다.

@Inherited 어노테이션을 사용하여 어노테이션이 어노테이션이있는 클래스에서 하위 클래스로 전파되도록 할 수 있습니다 .

우리가 적용 할 경우 @Inherited 다음 우리의 사용자 정의 주석과에 적용 BaseClass로 :

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotation {
}

@InheritedAnnotation
public class BaseClass {
}

public class DerivedClass extends BaseClass {
}

그런 다음 BaseClass를 확장 한 후 DerivedClass 가 런타임에 동일한 주석을 갖는 것으로 나타납니다.

@Test
public void whenAnnotationInherited_thenShouldExist() {
    DerivedClass derivedClass = new DerivedClass();
    InheritedAnnotation annotation = derivedClass.getClass()
      .getAnnotation(InheritedAnnotation.class);
 
    assertThat(annotation, instanceOf(InheritedAnnotation.class));
}

@Inherited 주석이 없으면 위의 테스트가 실패합니다.

4.4. @ 문서화

기본적으로 Java는 Javadocs의 주석 사용을 문서화하지 않습니다.

그러나 @Documented 주석을 사용하여 Java의 기본 동작을 변경할 수 있습니다 .

@Documented 를 사용하는 사용자 지정 주석을 만드는 경우 :

@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelCell {
    int value();
}

그리고 적절한 Java 요소에 적용하십시오.

public class Employee {
    @ExcelCell(0)
    public String name;
}

그런 다음 Employee Javadoc이 주석 사용법을 표시합니다.

4.5. @Repeatable

때때로 주어진 Java 요소에 동일한 어노테이션을 두 번 이상 지정하는 것이 유용 할 수 있습니다.

Java 7 이전에는 주석을 단일 컨테이너 주석으로 그룹화해야했습니다.

@Schedules({
    @Schedule(time = "15:05"),
    @Schedule(time = "23:00")
})
void scheduledAlarm() {
}

그러나 Java 7은 더 깨끗한 접근 방식을 가져 왔습니다. @Repeatable 주석, 우리는 주석 반복을 할 수 있습니다 :

@Repeatable(Schedules.class)
public @interface Schedule {
    String time() default "09:00";
}

@Repeatable 을 사용하려면 컨테이너 주석도 필요합니다 . 이 경우 @Schedules를 재사용 합니다 .

public @interface Schedules {
    Schedule[] value();
}

물론 이것은 Java 7 이전과 비슷해 보이지만 이제 값은 @Schedule 을 반복해야 할 때 래퍼 @Schedules 가 더 이상 지정되지 않는다는 것입니다 .

@Schedule
@Schedule(time = "15:05")
@Schedule(time = "23:00")
void scheduledAlarm() {
}

Java에는 래퍼 주석이 필요하기 때문에 Java 7 이전 주석 목록에서 반복 가능한 주석으로 쉽게 마이그레이션 할 수있었습니다.

5. 결론

이 기사에서는 모든 Java 개발자가 숙지해야하는 Java 내장 주석에 대해 설명했습니다.

항상 그렇듯이 기사의 모든 예제는 GitHub 에서 찾을 수 있습니다 .