수색…


소개

Java에서 주석은 Java 소스 코드에 추가 할 수있는 구문 메타 데이터의 한 형태입니다. 프로그램 자체에 포함되지 않은 프로그램에 대한 데이터제공 합니다. 주석은 주석이 달린 코드의 작동에 직접적인 영향을 미치지 않습니다. 클래스, 메소드, 변수, 매개 변수 및 패키지에 주석을 추가 할 수 있습니다.

통사론

  • @AnnotationName // '마커 주석'(매개 변수 없음)
  • @AnnotationName (someValue) // 'value'라는 이름으로 매개 변수를 설정합니다.
  • @AnnotationName (param1 = value1) // 명명 된 매개 변수
  • @AnnotationName (param1 = value1, param2 = value2) // 여러 개의 명명 된 매개 변수
  • @AnnotationName (param1 = {1, 2, 3}) // 명명 된 배열 매개 변수
  • @AnnotationName ({value1}) // 이름이 'value'인 매개 변수로 단일 요소가있는 배열

비고

매개 변수 유형

다음 유형의 상수 표현식뿐 아니라 이러한 유형의 배열도 매개 변수에 허용됩니다.

  • String
  • Class
  • 기본 유형
  • Enum 유형
  • 주석 유형

내장 주석

Standard Edition Java에는 미리 정의 된 일부 주석이 있습니다. 혼자서 정의 할 필요가 없으며 즉시 사용할 수 있습니다. 그것들은 컴파일러가 메소드, 클래스 및 코드의 근본적인 검사를 가능하게합니다.

@보수

이 주석은 메소드에 적용되며이 메소드는 수퍼 클래스의 메소드를 대체하거나 추상 수퍼 클래스의 메소드 정의를 구현해야한다고합니다. 이 주석을 다른 종류의 메서드와 함께 사용하면 컴파일러에서 오류가 발생합니다.

콘크리트 수퍼 클래스

public class Vehicle {
   public void drive() {
        System.out.println("I am driving");
   }
}

class Car extends Vehicle {
    // Fine
    @Override
    public void drive() {
        System.out.prinln("Brrrm, brrm");
    }
}

추상 클래스

abstract class Animal  {
   public abstract void makeNoise(); 
}

class Dog extends Animal {
    // Fine
    @Override
    public void makeNoise() {
        System.out.prinln("Woof");
    }
}

작동하지 않습니다.

class Logger1 {
    public void log(String logString) {
        System.out.prinln(logString);
    }
}

class Logger2 {
    // This will throw compile-time error. Logger2 is not a subclass of Logger1. 
    // log method is not overriding anything
    @Override
    public void log(String logString) {
        System.out.println("Log 2" + logString);
    }
}

주된 목적은 메서드를 재정의한다고 생각하는 실수 유형을 잡아내는 것이지만 실제로는 메서드를 재정의하는 것입니다.

class Vehicle {
   public void drive() {
        System.out.println("I am driving");
   }
}

class Car extends Vehicle {
    // Compiler error. "dirve" is not the correct method name to override.
    @Override
    public void dirve() {
        System.out.prinln("Brrrm, brrm");
    }
}

@Override 의 의미는 시간이 지남에 따라 변경되었습니다.

  • Java 5에서는 주석이 달린 메소드가 수퍼 클래스 체인에서 선언 된 비 추상적 인 메소드를 대체해야한다는 것을 의미했습니다.
  • Java 6 이후부터는 주석 된 메소드가 클래스 수퍼 클래스 / 인터페이스 계층에 선언 된 추상 메소드를 구현하는 경우 에도 만족합니다.

(코드를 Java 5로 다시 이식 할 때 가끔 문제가 발생할 수 있습니다.)

@Deprecated

이 메소드는 사용되지 않는 것으로 표시합니다. 이것에 대한 몇 가지 이유가있을 수 있습니다 :

  • API에 결함이 있으며 수정할 수 없습니다.

  • API를 사용하면 오류가 발생할 수 있습니다.

  • API는 다른 API에 의해 대체되었으며,

  • API는 더 이상 사용되지 않습니다.

  • API는 실험적이며 호환되지 않는 변경 사항이 적용됩니다.

  • 또는 상기의 임의의 조합.

비추천에 대한 구체적인 이유는 일반적으로 API의 문서에서 찾을 수 있습니다.


어노테이션을 사용하면 컴파일러가 오류를 내 보냅니다. IDE는이 방법을 어떻게 든 비추천으로 강조 할 수도 있습니다.

class ComplexAlgorithm {
    @Deprecated
    public void oldSlowUnthreadSafeMethod() {
        // stuff here
    }
    
    public void quickThreadSafeMethod() {
        // client code should use this instead
    }
}

@SuppressWarnings

거의 모든 경우 컴파일러에서 경고를 내면 가장 적절한 조치는 원인을 수정하는 것입니다. 예를 들어, 유형이 안전한 제네릭 코드를 사용하는 제네릭 코드는 가능하지 않을 수 있으며 예상치 못한 오류를 억제하여 예기치 못한 경고가 더 명확하게 표시 될 수 있습니다.

이 주석은 전체 클래스, 메소드 또는 라인에 적용 할 수 있습니다. 경고 카테고리를 매개 변수로 사용합니다.

@SuppressWarnings("deprecation")
public class RiddledWithWarnings {
    // several methods calling deprecated code here
}

@SuppressWarning("finally")
public boolean checkData() {
    // method calling return from within finally block
}

예상치 못한 경고가 표시되지 않도록 주석의 범위를 최대한 제한하는 것이 좋습니다. 예를 들어, 주석의 범위를 한 줄로 제한 :

ComplexAlgorithm algorithm = new ComplexAlgorithm();
@SuppressWarnings("deprecation") algoritm.slowUnthreadSafeMethod(); 
// we marked this method deprecated in an example above

@SuppressWarnings("unsafe") List<Integer> list = getUntypeSafeList(); 
// old library returns, non-generic List containing only integers

이 주석이 지원하는 경고는 컴파일러마다 다를 수 있습니다. JLS에서는 unchecked 않고 deprecation 경고 만 특별히 언급됩니다. 인식 할 수없는 경고 유형은 무시됩니다.

@SafeVarargs

형식 삭제 때문에 void method(T... t)void method(Object[] t) 로 변환되어 컴파일러가 항상 varargs의 사용이 형식에 관계가 있는지 확인할 수있는 것은 아닙니다. 예를 들면 :

private static <T> void generatesVarargsWarning(T... lists) {

사용이 안전한 경우가 있습니다.이 경우 경고를 표시하지 않으려면 SafeVarargs 주석을 사용하여 메서드에 주석을 추가 할 수 있습니다. 이것은 당신의 사용이 안전하지 않은 경우에도 분명히 경고를 숨 깁니다.

@ 기능적 인터페이스

FunctionalInterface를 표시하는 데 사용되는 선택적 주석입니다. FunctionalInterface 스펙 (단일 추상 메소드 있음)을 준수하지 않으면 컴파일러가 불평합니다.

@FunctionalInterface
public interface ITrade {
  public boolean check(Trade t);
}

@FunctionalInterface
public interface Predicate<T> {
  boolean test(T t);
}

리플렉션을 통한 런타임 주석 점검

Java의 Reflection API를 사용하면 프로그래머는 런타임 중에 클래스 필드, 메소드 및 주석에 대해 다양한 검사 및 연산을 수행 할 수 있습니다. 그러나 런타임에 주석을 모두 볼 수있게하려면 아래 예제와 같이 RetentionPolicyRUNTIME 으로 변경해야합니다.

@interface MyDefaultAnnotation {

}

@Retention(RetentionPolicy.RUNTIME)
@interface MyRuntimeVisibleAnnotation {

}

public class AnnotationAtRuntimeTest {

    @MyDefaultAnnotation
    static class RuntimeCheck1 {
    }
    
    @MyRuntimeVisibleAnnotation
    static class RuntimeCheck2 {
    }
    
    public static void main(String[] args) {
        Annotation[] annotationsByType = RuntimeCheck1.class.getAnnotations();
        Annotation[] annotationsByType2 = RuntimeCheck2.class.getAnnotations();

        System.out.println("default retention: " + Arrays.toString(annotationsByType));
        System.out.println("runtime retention: " + Arrays.toString(annotationsByType2));
    }
}

주석 유형 정의하기

주석 유형은 @interface 로 정의됩니다. 매개 변수는 일반 인터페이스의 메소드와 유사하게 정의됩니다.

@interface MyAnnotation {
    String param1();
    boolean param2();
    int[] param3();  // array parameter 
}

기본값

@interface MyAnnotation {
    String param1() default "someValue";
    boolean param2() default true;
    int[] param3() default {};
}

메타 주석

메타 주석은 주석 유형에 적용 할 수있는 주석입니다. 특별한 미리 정의 된 메타 - 어노테이션은 어노테이션 유형을 사용하는 방법을 정의합니다.

@목표

@Target 메타 - 어노테이션은 어노테이션을 적용 할 수있는 유형을 제한합니다.

@Target(ElementType.METHOD)
@interface MyAnnotation {
    // this annotation can only be applied to methods
}

배열 표기법을 사용하여 여러 값을 추가 할 수 있습니다 @Target({ElementType.FIELD, ElementType.TYPE}) 예 : @Target({ElementType.FIELD, ElementType.TYPE})

사용 가능한 값

요소 유형 목표 대상 요소의 사용 예
ANNOTATION_TYPE 주석 유형
@Retention(RetentionPolicy.RUNTIME) 
@interface MyAnnotation
건설자 생성자
@MyAnnotation
public MyClass() {}
필드, 열거 형 상수
@XmlAttribute
private int count;
LOCAL_VARIABLE 메소드 내부의 변수 선언
for (@LoopVariable int i = 0; i < 100; i++) {
@Unused
String resultVariable;
}
꾸러미 패키지 ( package-info.java )
@Deprecated
package very.old;
방법 행동 양식
@XmlElement
public int getCount() {...}
매개 변수 메서드 / 생성자 매개 변수
public Rectangle(
@NamedArg("width") double width,
@NamedArg("height") double height) {
...
}
유형 클래스, 인터페이스, 열거 형
@XmlRootElement
public class Report {}
Java SE 8
요소 유형 목표 대상 요소의 사용 예
TYPE_PARAMETER 형식 매개 변수 선언
public <@MyAnnotation T> void f(T t) {}
TYPE_USE 유형의 사용
Object o = "42";
String s = (@MyAnnotation String) o;

@보유

@Retention 메타 주석은 응용 프로그램 컴파일 프로세스 또는 실행 중에 주석 표시 여부를 정의합니다. 기본적으로 주석은 .class 파일에 포함되지만 런타임에는 표시되지 않습니다. 런타임시 주석에 액세스 할 수있게하려면 해당 주석에 RetentionPolicy.RUNTIME 을 설정해야합니다.

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    // this annotation can be accessed with reflections at runtime
}

사용 가능한 값

RetentionPolicy 효과
수업 주석은 .class 파일에서 사용할 수 있지만 런타임에는 사용할 수 없습니다.
실행 시간 주석은 런타임에 사용할 수 있으며 리플렉션을 통해 액세스 할 수 있습니다.
출처 주석은 컴파일시에 사용할 수 있지만 .class 파일에는 추가되지 않습니다. 주석은 예를 들어 주석 프로세서에서 사용할 수 있습니다.

@Documented @Documented

@Documented 메타 주석은 javadoc 과 같은 API 문서 생성기에서 사용법을 문서화해야하는 주석을 표시하는 데 사용됩니다. 가치가 없습니다. @Documented 를 사용하면 주석을 사용하는 모든 클래스가 생성 된 문서 페이지에 주석을 표시합니다. @Documented 없으면 문서의 주석을 사용하는 클래스를 확인할 수 없습니다.

@Inherited

@Inherited meta-annotation은 클래스에 적용되는 주석과 관련이 있습니다. 가치가 없습니다. 어노테이션을 @Inherited 로 표시하면 어노테이션 쿼리가 작동하는 방식이 변경됩니다.

  • 상속되지 않은 주석의 경우 쿼리는 검사 할 클래스 만 검사합니다.
  • 계승 된 주석의 경우, 쿼리는 주석의 인스턴스가 발견 될 때까지 수퍼 클래스 체인 (재귀 적으로)을 검사합니다.

수퍼 클래스 만 쿼리됩니다. 클래스 계층의 인터페이스에 연결된 모든 주석은 무시됩니다.

@ 반복 가능

@Repeatable 메타 주석은 Java 8에 추가되었습니다. 주석의 여러 인스턴스가 주석의 대상에 첨부 될 수 있음을 나타냅니다. 이 메타 주석에는 값이 없습니다.

런타임시 Annotation 값 가져 오기

Reflection 을 사용하여 Annotation이 적용된 Method 나 Field 또는 Class를 가져 와서 원하는 속성을 가져 와서 Annotation의 현재 속성을 가져올 수 있습니다.

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String key() default "foo";
    String value() default "bar";
}


class AnnotationExample {
    // Put the Annotation on the method, but leave the defaults
    @MyAnnotation
    public void testDefaults() throws Exception {
        // Using reflection, get the public method "testDefaults", which is this method with no args
        Method method = AnnotationExample.class.getMethod("testDefaults", null);

        // Fetch the Annotation that is of type MyAnnotation from the Method
        MyAnnotation annotation = (MyAnnotation)method.getAnnotation(MyAnnotation.class);

        // Print out the settings of the Annotation
        print(annotation);
    }

    //Put the Annotation on the method, but override the settings
    @MyAnnotation(key="baz", value="buzz")
    public void testValues() throws Exception {
        // Using reflection, get the public method "testValues", which is this method with no args
        Method method = AnnotationExample.class.getMethod("testValues", null);

        // Fetch the Annotation that is of type MyAnnotation from the Method
        MyAnnotation annotation = (MyAnnotation)method.getAnnotation(MyAnnotation.class);

        // Print out the settings of the Annotation
        print(annotation);
    }

    public void print(MyAnnotation annotation) {
        // Fetch the MyAnnotation 'key' & 'value' properties, and print them out 
        System.out.println(annotation.key() + " = " + annotation.value());
    }

    public static void main(String[] args) {
        AnnotationExample example = new AnnotationExample();
        try {
            example.testDefaults();
            example.testValues();
        } catch( Exception e ) {
            // Shouldn't throw any Exceptions
            System.err.println("Exception [" + e.getClass().getName() + "] - " + e.getMessage());
            e.printStackTrace(System.err);
        }
    }
}

출력은

foo = bar
baz = buzz

어노테이션 반복

Java 8까지는 동일한 주석의 두 인스턴스를 단일 요소에 적용 할 수 없었습니다. 표준 해결 방법은 다른 주석의 배열을 포함하는 컨테이너 주석을 사용하는 것이 었습니다.

// Author.java
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
    String value();
}

// Authors.java
@Retention(RetentionPolicy.RUNTIME)
public @interface Authors {
    Author[] value();
}

// Test.java
@Authors({
    @Author("Mary"),
    @Author("Sam")
})
public class Test {
    public static void main(String[] args) {
        Author[] authors = Test.class.getAnnotation(Authors.class).value();
        for (Author author : authors) {
            System.out.println(author.value());
            // Output:
            // Mary
            // Sam
        }
    }
}
Java SE 8

Java 8은 @Repeatable 어노테이션을 사용하여 컨테이너 주석을 사용하는보다 깔끔하고 투명한 방법을 제공합니다. 먼저 Author 클래스에 추가합니다.

@Repeatable(Authors.class)

이것은 자바에게 @Author 어노테이션으로 둘러싸인 것처럼 @Author 어노테이션을 여러개로 처리하도록 @Authors . Class.getAnnotationsByType() 을 사용하여 @Author 배열에 컨테이너가 아닌 자체 클래스로 액세스 할 수도 있습니다.

@Author("Mary")
@Author("Sam")
public class Test {
    public static void main(String[] args) {
        Author[] authors = Test.class.getAnnotationsByType(Author.class);
        for (Author author : authors) {
            System.out.println(author.value());
            // Output:
            // Mary
            // Sam
        }
    }
}

상속 된 주석

기본적으로 클래스 어노테이션은 클래스 어노테이션을 확장하는 유형에는 적용되지 않습니다. 주석 정의에 @Inherited 주석을 추가하여 변경할 수 있습니다.

다음의 2 가지 특수 효과를 고려하십시오.

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

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

다음과 같이 3 개의 클래스에 주석이 달린 경우 :

@UninheritedAnnotationType
class A {
}

@InheritedAnnotationType
class B extends A {
}

class C extends B {
}

이 코드를 실행

System.out.println(new A().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println(new B().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println(new C().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println("_________________________________");
System.out.println(new A().getClass().getAnnotation(UninheritedAnnotationType.class));
System.out.println(new B().getClass().getAnnotation(UninheritedAnnotationType.class));
System.out.println(new C().getClass().getAnnotation(UninheritedAnnotationType.class));

주석의 패키지에 따라 다음과 유사한 결과를 인쇄합니다.

null
@InheritedAnnotationType()
@InheritedAnnotationType()
_________________________________
@UninheritedAnnotationType()
null
null

주석은 인터페이스가 아닌 클래스에서만 상속 될 수 있습니다.

주석 처리기를 사용하여 컴파일 시간 처리

이 예제는 주석 요소의 컴파일 시간 검사를 수행하는 방법을 보여줍니다.

주석

@Setter 주석은 메소드에 적용 할 수있는 마커입니다. 나중에 주석을 컴파일 할 수 없으면 삭제됩니다.

package annotation;

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

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

어노테이션 프로세서

SetterProcessor 클래스는 주석을 처리하기 위해 컴파일러에서 사용됩니다. 주석 방법 경우는 확인 @Setter 주석이 public , 비 static 이름으로 시작과 방법 set , 4 글자로 대문자를 가지고가. 이러한 조건 중 하나가 충족되지 않으면 오류가 Messager 기록됩니다. 컴파일러는이를 stderr에 기록하지만 다른 도구는이 정보를 다르게 사용할 수 있습니다. 예를 들어, NetBeans IDE를 사용하면 편집기에 오류 메시지를 표시하는 데 사용되는 주석 프로세서를 지정할 수 있습니다.

package annotation.processor;

import annotation.Setter;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;

@SupportedAnnotationTypes({"annotation.Setter"})
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class SetterProcessor extends AbstractProcessor {

    private Messager messager;

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // get elements annotated with the @Setter annotation
        Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(Setter.class);

        for (Element element : annotatedElements) {
            if (element.getKind() == ElementKind.METHOD) {
                // only handle methods as targets
                checkMethod((ExecutableElement) element);
            }
        }

        // don't claim annotations to allow other processors to process them
        return false;
    }

    private void checkMethod(ExecutableElement method) {
        // check for valid name
        String name = method.getSimpleName().toString();
        if (!name.startsWith("set")) {
            printError(method, "setter name must start with \"set\"");
        } else if (name.length() == 3) {
            printError(method, "the method name must contain more than just \"set\"");
        } else if (Character.isLowerCase(name.charAt(3))) {
            if (method.getParameters().size() != 1) {
                printError(method, "character following \"set\" must be upper case");
            }
        }

        // check, if setter is public
        if (!method.getModifiers().contains(Modifier.PUBLIC)) {
            printError(method, "setter must be public");
        }

        // check, if method is static
        if (method.getModifiers().contains(Modifier.STATIC)) {
            printError(method, "setter must not be static");
        }
    }

    private void printError(Element element, String message) {
        messager.printMessage(Diagnostic.Kind.ERROR, message, element);
    }

    @Override
    public void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);

        // get messager for printing errors
        messager = processingEnvironment.getMessager();
    }

}

포장

컴파일러에서 적용하려면 SPI에서 주석 처리기를 사용할 수 있어야합니다 ( ServiceLoader 참조).

이 작업을 수행하려면 텍스트 파일 META-INF/services/javax.annotation.processing.Processor 를 다른 파일과 함께 주석 프로세서와 주석이 포함 된 jar 파일에 추가해야합니다. 파일에는 주석 프로세서의 정규화 된 이름이 포함되어야합니다. 즉, 다음과 같아야합니다.

annotation.processor.SetterProcessor

jar 파일이 아래의 AnnotationProcessor.jar 라고 가정합니다.

주석이 달린 클래스의 예

다음 클래스는 보존 정책에 따라 올바른 요소에 주석이 적용된 기본 패키지의 예제 클래스입니다. 그러나 주석 프로세서 만이 두 번째 방법을 유효한 주석 대상으로 간주합니다.

import annotation.Setter;

public class AnnotationProcessorTest {
    
    @Setter
    private void setValue(String value) {}

    @Setter
    public void setString(String value) {}
    
    @Setter
    public static void main(String[] args) {}
    
}

javac에 주석 프로세서 사용

주석 처리기가 SPI를 사용하여 검색되면 주석 처리 된 요소를 처리하는 데 자동으로 사용됩니다. 예 : AnnotationProcessorTest 클래스를 사용하여 컴파일

javac -cp AnnotationProcessor.jar AnnotationProcessorTest.java

다음 출력을 산출합니다.

AnnotationProcessorTest.java:6: error: setter must be public
    private void setValue(String value) {}
                 ^
AnnotationProcessorTest.java:12: error: setter name must start with "set"
    public static void main(String[] args) {}
                       ^
2 errors

정상적으로 컴파일하는 대신 .class 파일이 작성되지 않습니다.

javac 대해 -proc:none 옵션을 지정하면이 문제를 방지 할 수 있습니다. 대신 -proc:only 를 지정하여 일반적인 컴파일 작업을 수행하지 -proc:only 됩니다.

IDE 통합

넷빈

NetBeans 편집기에서 주석 처리기를 사용할 수 있습니다. 이렇게하려면 프로젝트 설정에서 주석 프로세서를 지정해야합니다.

  1. Project Properties > Build > Compiling 로 이동 Build

  2. Enable Annotation Processing Enable Annotation Processing in EditorEnable Annotation Processing in Editor 대한 확인 표시를 추가하십시오.

  3. 주석 프로세서 목록 옆에있는 Add 클릭 Add

  4. 주석 프로세서의 정규화 된 클래스 이름을 입력하고 클릭 나타나는 팝업에서 Ok .

결과

사용자 정의 오류 메시지가 표시된 편집기 창

특수 효과 뒤에 숨겨진 아이디어

Java 언어 사양 은 주석을 다음과 같이 설명합니다.

주석은 정보를 프로그램 구조와 연관 시키지만 런타임에는 영향을 미치지 않는 표식입니다.

주석은 유형 또는 선언 앞에 나타날 수 있습니다. 유형이나 선언문 모두에 적용 할 수있는 장소에 나타날 수 있습니다.
주석이 정확히 적용되는 것은 "메타 주석" @Target 에 의해 관리됩니다. 자세한 내용은 "주석 유형 정의" 를 참조하십시오.

주석은 여러 목적으로 사용됩니다. Spring 및 Spring-MVC와 같은 프레임 워크는 주석을 사용하여 종속성을 주입해야하는 위치 또는 요청을 라우팅해야하는 위치를 정의합니다.

다른 프레임 워크는 코드 생성을 위해 주석을 사용합니다. 롬복과 JPA는 Java (및 SQL) 코드를 생성하기 위해 주석을 사용하는 대표적인 예입니다.

이 주제는 다음에 대한 포괄적 인 개요를 제공합니다.

  • 자신의 특수 효과를 정의하는 방법은 무엇입니까?

  • 자바 언어는 어떤 주석을 제공합니까?

  • 특수 효과는 실제로 어떻게 사용됩니까?

'this'및 수신기 매개 변수에 대한 주석

Java 어노테이션이 처음 도입되었을 때 인스턴스 메소드의 대상이나 내부 클래스 생성자에 대한 숨겨진 생성자 매개 변수에 주석을 달 수있는 조항이 없었습니다. 이것은 Java 8에서 수신기 매개 변수 선언을 추가하여 해결되었습니다. JLS 8.4.1을 참조하십시오.

receiver 매개 변수는 인스턴스 메소드 또는 내부 클래스의 생성자에 대한 선택적 구문 장치입니다. 인스턴스 메소드의 경우, receiver 매개 변수는 메소드가 호출되는 오브젝트를 나타냅니다. 내부 클래스의 생성자의 경우 receiver 매개 변수는 새로 생성 된 객체를 즉시 포함하는 인스턴스를 나타냅니다. 어느 쪽이든, 리시버 매개 변수는 표시된 오브젝트의 유형을 소스 코드로 표시 할 수 있도록하기 위해 존재하기 때문에 유형에 주석을 달 수 있습니다. receiver 매개 변수는 형식적인 매개 변수가 아닙니다. 보다 정확하게는 어떤 종류의 변수 (4.12.3) 선언도 아니며 메서드 호출 표현식이나 정규화 된 클래스 인스턴스 작성 표현식에서 인수로 전달 된 값에 바인드되지 않으며 실행 시간.

다음 예제에서는 두 종류의 수신자 매개 변수에 대한 구문을 보여줍니다.

public class Outer {
    public class Inner {
        public Inner (Outer this) {
           // ...
        }
        public void doIt(Inner this) {
           // ...
        }
    }
}

리시버 매개 변수의 유일한 목적은 주석을 추가 할 수있게하는 것입니다. 예를 들어, 메서드 호출시 Closeable 객체가 닫혀지지 않았다는 것을 나타내는 목적으로 @IsOpen 이라는 커스텀 어노테이션을 @IsOpen 수 있습니다. 예 :

public class MyResource extends Closeable {
    public void update(@IsOpen MyResource this, int value) {
        // ...
    }

    public void close() {
        // ...
    }
}

한 레벨에서, @IsOpen 에 주석 this 단순히 문서의 역할을 할 수있다. 그러나 우리는 잠재적으로 더 많은 것을 할 수 있습니다. 예 :

  • 주석 프로세서는 update 가 호출 될 때 this 닫힌 상태가 아니라는 런타임 검사를 삽입 할 수 있습니다.
  • 코드 검사기는 정적 코드 분석을 수행하여 update 가 호출 될 때 this 닫힐 수있는 경우를 찾습니다.

여러 주석 값 추가

Annotation 매개 변수는 배열로 정의 된 경우 여러 값을 허용 할 수 있습니다. 예를 들어 표준 주석 @SuppressWarnings 은 다음과 같이 정의됩니다.

public @interface SuppressWarnings {
    String[] value();
}

value 매개 변수는 문자열 배열입니다. 배열 이니셜 라이저와 비슷한 표기법을 사용하여 여러 값을 설정할 수 있습니다.

@SuppressWarnings({"unused"})
@SuppressWarnings({"unused", "javadoc"})

단일 값만 설정해야하는 경우 대괄호를 생략 할 수 있습니다.

@SuppressWarnings("unused") 


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow