Ответ 1
Строка public static <T> [email protected] Optional<T> toJavaUtil
написана так, потому что обычный стиль public static <T> @Nullable java.util.Optional<T> toJavaUtil
недопустим. Это определено в JLS §9.7.4:
Это ошибка времени компиляции, если аннотация типа T применяется к типу (или любой части типа) в контексте типа, а T применима в контекстах типа, а аннотация недопустима.
Например, предположим, что тип аннотации TA мета-аннотируется просто
@Target(ElementType.TYPE_USE)
. Термины@TA java.lang.Object
и[email protected] lang.Object
являются недопустимыми, потому что простое имя, к которому ближе всего @TA, классифицируется как имя пакета. С другой стороны,[email protected] Object
является законным.
Объявление типа [email protected]
:
@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
}
([TG412] is a local class where I copied the Guava code in, in order to get a minimal example to de-/compile)
Как видите, аннотации там больше не существует. Это только маркер для компилятора, который предотвращает предупреждение, когда метод возвращает null (и подсказку для читателей исходного кода), но он не будет включен в скомпилированный код.
Эта ошибка компилятора также относится к таким переменным, как:
private @Nullable2 java.util.Optional<?> o;
Но может стать приемлемым, когда аннотация дополнительно получает целевой тип ElementType.FIELD
, как написано в том же предложении JLS:
Если TA дополнительно мета-аннотируется с помощью
@Target(ElementType.FIELD)
, то термин@TA java.lang.Object
является допустимым в местоположениях, которые являются как декларацией, так и контекстами типа, такими как объявление поля@TA java.lang.Object f;
. Здесь @TA считается применимым к объявлению f (а не к типу java.lang.Object), потому что TA применяется в контексте объявления поля.