Program Tip

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

programtip 2020. 10. 5. 20:38
반응형

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


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

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)어쨌든 그랬어 야했던 것처럼 보임) 같은 일에 편리해 보이지만 다른 많은 주석의 경우 런타임에 여러 가지 나쁜 일이 발생할 수있는 것처럼 보입니다.


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

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

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


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은 주석이 바이너리로 컴파일되지만 바이너리에있는 주석은 런타임에 사용할 필요가 없음을 보장합니다.


실제로 @A를 읽는 코드가있는 경우 코드는 클래스 A에 대한 종속성을 가지며 ClassNotFoundException을 발생시킵니다.

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

참고 URL : https://stackoverflow.com/questions/3567413/why-doesnt-a-missing-annotation-cause-a-classnotfoundexception-at-runtime

반응형