누락 된 주석으로 인해 런타임에 ClassNotFoundException이 발생하지 않는 이유는 무엇입니까?


91

다음 코드를 고려하십시오.

A.java :

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

@Retention(RetentionPolicy.RUNTIME)
@interface A{}

C.java :

import java.util.*;

@A public class C {
        public static void main(String[] args){
                System.out.println(Arrays.toString(C.class.getAnnotations()));
        }
}

컴파일 및 실행은 예상대로 작동합니다.

$ javac *.java
$ java -cp . C
[@A()]

그러나 다음을 고려하십시오.

$ rm A.class
$ java -cp . C
[]

가 누락 ClassNotFoundException되었기 때문에 나는 던질 것으로 예상했을 것 @A입니다. 그러나 대신 주석을 자동으로 삭제합니다.

이 동작이 JLS 어딘가에 문서화되어 있습니까, 아니면 Sun의 JVM의 특징입니까? 그 이유는 무엇입니까?

javax.annotation.Nonnull( @Retention(CLASS)어쨌든 그래야 할 것처럼 보임) 같은 일에 편리해 보이지만 다른 많은 주석의 경우 런타임에 여러 가지 나쁜 일이 발생할 수 있습니다.

답변:


90

JSR-175 (주석)에 대한 이전 공개 초안에서 컴파일러와 런타임이 알 수없는 주석을 무시해야하는지 여부에 대해 논의하여 주석의 사용과 선언 사이에 느슨한 결합을 제공했습니다. 특정 예는 배포 구성을 제어하기 위해 EJB에서 애플리케이션 서버 특정 주석을 사용하는 것입니다. 동일한 Bean이 다른 애플리케이션 서버에 배치되어야하는 경우 런타임이 NoClassDefFoundError를 발생시키는 대신 알 수없는 어노테이션을 무시하면 편리했을 것입니다.

문구가 약간 모호하더라도 JLS 13.5.7에 지정되어 있다고 가정합니다. "... 주석을 제거해도 Java 프로그래밍 언어에서 프로그램의 이진 표현의 올바른 연결에 영향을주지 않습니다. . " 주석이 제거 된 것처럼 (런타임에 사용할 수 없음) 프로그램은 계속 연결되고 실행되어야하며 이는 리플렉션을 통해 액세스 할 때 알 수없는 주석이 단순히 무시된다는 것을 의미합니다.

Sun의 JDK 5의 첫 번째 릴리스는이를 올바르게 구현하지 못했지만 1.5.0_06에서 수정되었습니다. 버그 데이터베이스에서 관련 버그 6322301 을 찾을 수 있지만 "JSR-175 사양 리드에 따라 getAnnotations에서 알 수없는 주석을 무시해야합니다"라는 주장을 제외하고는 사양을 가리 키지 않습니다.


35

JLS 인용 :

9.6.1.2 Retention Annotations는 소스 코드에만 존재하거나 클래스 또는 인터페이스의 이진 형태로 존재할 수 있습니다. 바이너리에 존재하는 주석은 Java 플랫폼의 반사 라이브러리를 통해 런타임에 사용 가능할 수도 있고 사용 가능하지 않을 수도 있습니다.

주석 유형 annotation.Retention은 위의 가능성 중에서 선택하는 데 사용됩니다. 주석 a가 T 유형에 해당하고 T에 annotation.Retention에 해당하는 (메타) 주석 m이있는 경우 :

  • m에 값이 annotation.RetentionPolicy.SOURCE 인 요소가있는 경우 Java 컴파일러는 a가 나타나는 클래스 또는 인터페이스의 이진 표현에 a가 없는지 확인해야합니다.
  • m에 값이 annotation.RetentionPolicy.CLASS 또는 annotation.RetentionPolicy.RUNTIME 인 요소가있는 경우 Java 컴파일러는 m이 지역 변수 선언에 주석을 달지 않는 한 a가 나타나는 클래스 또는 인터페이스의 이진 표현에 a가 표시되는지 확인해야합니다. . 지역 변수 선언에 대한 주석은 이진 표현에 유지되지 않습니다.

T에 annotation.Retention에 해당하는 (meta-) annotation m이 없으면 Java 컴파일러는 값이 annotation.RetentionPolicy.CLASS 인 요소가있는 메타 주석 m이있는 것처럼 T를 처리해야합니다.

따라서 RetentionPolicy.RUNTIME은 주석이 바이너리로 컴파일되지만 바이너리에있는 주석은 런타임에 사용할 필요가 없음을 보장합니다.


9

실제로 @A를 읽는 코드가있는 경우 코드는 클래스 A에 종속되며 ClassNotFoundException이 발생합니다.

그렇지 않다면, 즉 코드가 @A에 대해 특별히 신경 쓰지 않는 경우 @A가 실제로 중요하지 않다는 것은 논쟁의 여지가 있습니다.

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