@Override와 같은 주석은 Java에서 내부적으로 어떻게 작동합니까?


93

아무도 주석이 Java에서 내부적으로 어떻게 작동하는지 설명해 줄 수 있습니까?

Java에서 java.lang.annotation 라이브러리를 사용하여 사용자 지정 주석을 만드는 방법을 알고 있습니다. 하지만 여전히 내부적으로 작동하는 방식을 알 수 없습니다 (예 : @Override 주석).

자세히 설명해 주시면 정말 감사하겠습니다.


4
"내부 작업"이란 무엇을 의미합니까? 컴파일러? 런타임?
chrylis -cautiouslyoptimistic-

3
@chrylis Work는 내부적으로이 메서드가 재정의 메서드인지 아니면 재정의 메서드가 아닌지 자동으로 식별하는 방법을 의미합니다. 두 시간 모두 작업입니다. 같은 컴파일 시간과 봄 컨트롤러 주석의 재정의 주석 작업은 런타임 작업입니다
치라 다사니

답변:


138

어노테이션 종류의 첫 번째 주요 차이점은 컴파일 타임에 사용 된 다음 폐기 (예 :) @Override또는 컴파일 된 클래스 파일에 배치되고 런타임시 (예 : Spring 's @Component) 사용할 수 있는지 여부 입니다. 이는 주석 의 @Retention 정책에 의해 결정됩니다 . 고유 한 주석을 작성하는 경우 주석이 런타임 (자동 구성 등)에 도움이되는지 아니면 컴파일 시간에만 (검사 또는 코드 생성에) 유용한 지 결정해야합니다.

주석이 포함 된 코드를 컴파일 할 때 컴파일러는 액세스 수정 자 ( public/ private) 또는 같은 소스 요소의 다른 수정자를 보는 것처럼 주석을 봅니다 final. 어노테이션을 발견하면 특정 어노테이션에 관심이 있다고 말하는 플러그인 클래스와 같은 어노테이션 프로세서를 실행합니다. 주석 프로세서는 일반적으로 Reflection API를 사용하여 컴파일되는 요소를 검사하고 단순히 검사를 실행하거나 수정하거나 컴파일 할 새 코드를 생성 할 수 있습니다. @Override첫 번째의 예입니다. 리플렉션 API를 사용하여 슈퍼 클래스 중 하나에서 메서드 시그니처에 대한 일치 항목을 찾을 수 있는지 확인하고를 사용하여 Messager불가능한 경우 컴파일 오류를 발생시킵니다.

주석 처리기 작성에 대한 많은 자습서가 있습니다. 여기에 유용한 것이 있습니다. 컴파일러가 어노테이션 프로세서를 호출하는 방법에 대해서는 Processor인터페이스 의 메소드를 살펴보십시오 . 주요 작업은 process메서드에서 발생하며 컴파일러가 일치하는 주석이있는 요소를 볼 때마다 호출됩니다.


4
Spring의 어노테이션 프로세서가 @Component를 구문 분석하고 컨테이너에 클래스를 주입하는 방법을 정확히 알려 주면 좋을 것입니다.
Junchen Liu

@shanyangqu 그것은 Spring에 국한되지 않는 질문에 대한 주제를 벗어났습니다. 포스트 프로세서 클래스를 직접 읽을 수 있습니다.
chrylis -cautiouslyoptimistic-

42

다른 사람들이 제안한 것 외에도 주석이 어떻게 작동하는지 확인하기 위해 사용자 지정 주석과 프로세서를 처음부터 작성하는 것이 좋습니다.

예를 들어, 필자는 컴파일 타임에 메서드가 오버로드되었는지 확인하기 위해 주석을 작성했습니다.

먼저라는 주석을 만듭니다 Overload. 이 주석은 메서드에 적용되므로@Target(value=ElementType.METHOD)

package gearon.customAnnotation;

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

@Target(value=ElementType.METHOD)
public @interface Overload {

}

다음으로 정의 된 주석으로 주석이 달린 요소를 처리 할 해당 프로세서를 만듭니다. 로 주석이 달린 메소드 @Overload의 경우 서명이 두 번 이상 나타나야합니다. 또는 오류가 인쇄됩니다.

package gearon.customAnnotation;

import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;

@SupportedAnnotationTypes("gearon.customAnnotation.Overload")

public class OverloadProcessor extends AbstractProcessor{

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // TODO Auto-generated method stub
        HashMap<String, Integer> map = new HashMap<String, Integer>();

        for(Element element : roundEnv.getElementsAnnotatedWith(Overload.class)){
            String signature = element.getSimpleName().toString();
            int count = map.containsKey(signature) ? map.get(signature) : 0;
            map.put(signature, ++count);
        }

        for(Entry<String, Integer> entry: map.entrySet()){
            if(entry.getValue() == 1){
                processingEnv.getMessager().printMessage(Kind.ERROR, "The method which signature is " + entry.getKey() +  " has not been overloaded");
            }
        }
        return true;
    }
}

주석 및 해당 프로세스를 jar 파일로 패키징 한 후 @Overloadjavac.exe를 사용 하여 클래스를 만들고 컴파일합니다.

import gearon.customAnnotation.Overload;

public class OverloadTest {
    @Overload
    public static void foo(){
    }

    @Overload
    public static void foo(String s){

    }

    @Overload
    public static void nonOverloadedMethod(){

    }
} 

nonOverloadedMethod()실제로 오버로드되지 않았 으므로 다음과 같은 출력을 얻습니다.

여기에 이미지 설명 입력


위의 정보는 JDK6 (+1)에 대한 매우 좋은 존중이지만 JDK5를 사용하여 동일한 결과를 얻는 방법은 무엇입니까? JDK6 SupportedAnnotationTypes, AbstractProcessor 클래스를 사용하면 더 간단 해졌지만 과거에 같은 일이 어떻게 일어 났습니까 (jdk5의 Spring FrameWork 2.5)? JVM이 jdk5의 클래스와 같은 주석 프로세서를 어떻게 감지합니까? 2 섹션 (JDK5 용, 현재 버전은 Jdk6 + 용)의 답변을 편집하여 안내해 주시겠습니까?
prajitgandhi

수업에서 OverloadProcessor::process왜 그렇 entry.getValue() == 1습니까? 부모 클래스 / 인터페이스에 주석을 추가 할 필요가 없으므로 부모 클래스 / 인터페이스를 roundEnv.getElementsAnnotatedWith(Overload.class)얻지 못할 것입니다.
비가

이 부분에서 혼란 스럽지만 귀하의 답변이 매우 도움이되었다고 생각합니다.
비가

@ s̮̦̩e̝͓c̮͔̞ṛ̖̖e̬̣̦t̸͉̥̳̼ 메서드가 오버로드로 취급되는 경우 클래스에 정의 된 동일한 이름을 가진 다른 메서드가 하나 이상 있어야합니다.
유진

1
@Raining 메서드가 Overloaded라고 말하면 같은 클래스에 두 번 이상 나타나야하지만`== 1`이면 오류입니다.
KrishPrabakar

5

여기 @Override: http://www.docjar.com/html/api/java/lang/Override.java.html .

직접 작성할 수있는 주석과 구별되는 특별한 점은 없습니다. 흥미로운 부분은 주석 의 소비자 입니다. 와 같은 주석의 @Override경우 Java 컴파일러 자체, 정적 코드 분석 도구 또는 IDE에 있습니다.


1
Override 주석의 소스 코드를 알고 있습니다. 그러나 내부적으로는 어떻게 작동하는지. 어떻게 식별 할 수 있는지이 방법이 재정의 방법이 아니거나이 방법이 재정의 방법입니까? 또는 사용자 지정 재정의 주석을 만들 수 있습니까? 그것은 자바 재정의 주석처럼 정확하게 같은 동작 작품이어야한다
치라 다사니

3
내 대답에서 말했듯 이 동작은 주석의 일부가 아닙니다. 해석은 주석을 소비하는 것들에 있습니다. 따라서 소비자를 변경하지 않는 한 실제로 사용자 정의 버전 @Override(또는 기타 표준 주석)을 만들 수 없습니다 .
Matt Ball

3

기본적으로 주석은 컴파일러 나 응용 프로그램에서 읽는 마커 일뿐입니다. 보존 정책에 따라 컴파일 타임에만 사용할 수 있거나 리플렉션을 사용하여 런타임에 읽을 수 있습니다.

많은 프레임 워크는 런타임 보존을 사용합니다. 즉, 클래스, 메서드, 필드 등에 일부 주석이 있는지 여부를 반사적으로 확인하고 주석이 있는지 여부에 따라 작업을 수행합니다. 또한 주석의 구성원을 사용하여 추가 정보를 전달할 수 있습니다.


3

링크를 따르십시오 . 이것은 귀하의 문제에 대한 가까운 답변을 제공 할 것입니다. 에서 주석에 초점을 맞춘 경우 주석은 JavaJava 5에서 도입되었으며 Spring에만 국한되지 않습니다. 일반적으로 주석을 사용하면 클래스, 메서드 또는 변수에 메타 데이터를 추가 할 수 있습니다. 주석은 컴파일러 (예 : @Override 주석) 또는 Spring과 같은 프레임 워크 (예 : @Component 주석)에서 해석 할 수 있습니다.

또한 더 많은 참조를 추가하고 있습니다.

  1. http://www.codeproject.com/Articles/272736/Understanding-Annotations-in-Java
  2. http://docs.oracle.com/javase/7/docs/api/java/lang/annotation/package-summary.html
  3. http://www.coderanch.com/how-to/java/AnnotationsExample

@LuiggiMendoza 자바 1.7 주석 문서 추가
Ruchira Gayan Ranaweera에게

@Ruchira 나는 모든 링크를 열었지만 여전히 작동 방식이 명확하지 않습니다. 봄 주석으로 고려하는 것과 같이 자세히 설명해 주시겠습니까? spring.xml 파일에 구성을 작성하지 않고 주석을 사용하여 모든 것을 할 수 있습니다. 내부적으로 주석을 xml 구성에 바인딩합니까?
살짝 다사니

@ChiragDasani가 이것을보세요. 이것은 당신에게 도움이 될 수 static.springsource.org/spring/docs/3.0.0.M3/reference/html/...을 하고이 SO 포스트 참조 stackoverflow.com/questions/2798181/...
Ruchira Gayan Ranaweera

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.