일부 코드 에서 주석 을 찾은 구아바 코드를 읽고 java.util.@Nullable
있습니다. 의 의미는 알지만 @Nullable
이해하지 못합니다. 특히 Nullable
패키지에서 호출 된 클래스를 찾을 수 없습니다 java.util
. 누군가가 이것의 의미가 무엇인지 말해주십시오 java.util.@Nullable
.
public static <T> java.util.@Nullable Optional<T> toJavaUtil(
@Nullable Optional<T> googleOptional) {
return googleOptional == null ? null : googleOptional.toJavaUtil();
}
답변
public static <T> java.util.@Nullable Optional<T> toJavaUtil
일반적인 스타일 public static <T> @Nullable java.util.Optional<T> toJavaUtil
이 유효하지 않기 때문에 행 은 다음과 같이 작성 됩니다. 이것은 JLS §9.7.4에 정의되어 있습니다 .
T 유형의 주석이 유형 컨텍스트의 유형 (또는 유형의 일부)에 적용되고 T가 유형 컨텍스트에 적용 가능하고 주석이 허용되지 않으면 컴파일 타임 오류입니다.
예를 들어 just로 메타 주석이 달린 주석 유형 TA를 가정하십시오
@Target(ElementType.TYPE_USE)
. 용어@TA java.lang.Object
와는java.@TA lang.Object
단순한 이름이있는에 @TA가 가장 가까운 패키지 이름으로 분류되어 있기 때문에 불법이다. 반면에java.lang.@TA Object
합법적입니다.
유형 선언 org.checkerframework.checker.nullness.qual@Nullable
은 다음과 같습니다.
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
이 규칙에 적용됩니다.
패키지 java.util
와 클래스 이름 Optional
이 분리되어 있기 때문에이 구조가 실행을 중단시키지 않는다는 것은 다음을 사용하여 컴파일 된 코드를 볼 때 볼 수 있습니다 javap -c [compiled class name]
.
class just.a.test.Main {
just.a.test.Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static <T> java.util.Optional<T> toJavaUtil(blub.Optional<T>);
Code:
0: aload_0
1: ifnonnull 8
4: aconst_null
5: goto 12
8: aload_0
9: invokevirtual #2 // Method blub/Optional.toJavaUtil:()Ljava/util/Optional;
12: areturn
}
( blub.Optional
디 컴파일 / 컴파일하기위한 최소한의 예제를 얻기 위해 Guava 코드를 복사 한 로컬 클래스입니다)
보시다시피 주석은 더 이상 존재하지 않습니다. 메소드가 널 (및 소스 코드 리더에 대한 힌트)을 리턴 할 때 경고를 방지하는 것은 컴파일러의 마커 일 뿐이지 만 컴파일 된 코드에는 포함되지 않습니다.
이 컴파일러 오류는 다음과 같은 변수에도 적용됩니다.
private @Nullable2 java.util.Optional<?> o;
그러나 주석 ElementType.FIELD
이 동일한 JLS 절에 작성된대로 대상 유형을 추가로 가져 오면 허용 될 수 있습니다 .
TA에 추가로 메타 주석이 추가 된 경우 필드 선언과 같이 선언 및 유형 컨텍스트가 모두있는 위치에서이
@Target(ElementType.FIELD)
용어@TA java.lang.Object
가 유효합니다@TA java.lang.Object f;
. 여기서 TA는 필드 선언 컨텍스트에 적용 할 수 있으므로 @TA는 f 선언 (java.lang.Object 유형이 아닌)에 적용되는 것으로 간주됩니다.
답변
주석을 사용할 때 import 문을 추가하는 대신 형식의 정규화 된 이름을 쓰려고 할 때 사용되는 구문입니다.
체커 프레임 워크 매뉴얼 에서 인용 :
정규화 된 유형 이름에 주석을 작성하는 올바른 Java 구문은 java.util. @ Nullable List에서와 같이 단순 이름 부분에 주석을 추가하는 것입니다. 그러나 소스 파일에 import java.util.List를 추가하면 @Nullable List 만 작성할 수 있습니다.
여기에서 다운로드 할 수있는 JSR308 사양의 2 페이지에 나와 있습니다 . 그것은 말한다 :
@NonNull String 또는 java.lang. @ NonNull String과 같이 형식의 간단한 이름 앞에 형식 주석이 나타납니다.
답변
여기서 이상한 점은 실제로 ElementType.TYPE_USE
-targeted 주석 을 적용하는 익숙하지 않은 구문입니다 . 당신이 선택하면 Null 허용 의 문서를, 당신은 낯선 대상을 볼 수 있습니다 :
...
@Target(value={TYPE_USE,TYPE_PARAMETER})
<public @interface Nullable
...
이 주석은 다음 두 가지 모두와 같이 주석이 달린 유형의 단순 이름 바로 앞에 사용됩니다.
public static <T> @Nullable Optional<T> toJavaUtil
public static <T> java.util.@Nullable Optional<T> toJavaUtil
나는 이런 종류의 대상이 무엇인지 알지 못했기 때문에 빠른 읽기 후에이 간단한 예제를 보았습니다.이 예제는 해당 대상이있는 주석을 사용하여 반환 유형 메타 데이터를 선택합니다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@interface InterceptedReturnValue {
boolean value() default true;
}
그리고 다음을 사용하여 처리했습니다.
public java.lang.@InterceptedReturnValue(true) String testMethod(String param) {
return null;
}
public @InterceptedReturnValue(false) String testMethod(int param) {
return null;
}
public static void main(String[] args) throws Exception {
Method m = Main.class.getDeclaredMethod("testMethod", String.class);
if(m.getAnnotatedReturnType().isAnnotationPresent(InterceptedReturnValue.class)) {
InterceptedReturnValue config = m.getAnnotatedReturnType()
.getAnnotation(InterceptedReturnValue.class);
if(config.value()) {
//logging return value enabled
}
}
}
체커 프레임 워크와 같은 많은 유용한 프레임 워크가 가장 적절하게 사용된다고 확신합니다. ElementType.TYPE_USE