Java >> Java tutorial >  >> Tag >> protected

Hvad er meningen med [e-mail beskyttet]?

Linjen public static <T> [email protected] Optional<T> toJavaUtil er skrevet sådan, fordi den sædvanlige stilart public static <T> @Nullable java.util.Optional<T> toJavaUtil er ugyldig. Dette er defineret i JLS §9.7.4:

Det er en kompileringsfejl, hvis en annotering af type T gælder for en type (eller en hvilken som helst del af en type) i en typekontekst, og T er anvendelig i typekontekster, og annoteringen er ikke tilladt. stærk>

Antag for eksempel en annotationstype TA, som er meta-annoteret med kun @Target(ElementType.TYPE_USE) . Begreberne @TA java.lang.Object og [email protected] lang.Object er ulovlige, fordi det simple navn, som @TA er tættest på, er klassificeret som et pakkenavn. På den anden side, [email protected] Object er lovligt.

Typeerklæringen [email protected] er:

@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})

Så det gælder for denne regel.

At denne struktur ikke bryder udførelsen, da pakke java.util og klassenavn Optional blev opdelt, kan ses, når vi ser på den kompilerede kode ved hjælp af 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 er en lokal klasse, hvor jeg kopierede Guava-koden ind, for at få et minimalt eksempel at de-/kompilere)

Som du kan se, eksisterer annotationen der ikke længere. Det er kun en markør for compileren for at forhindre en advarsel, når metoden returnerer null (og et tip til kildekodelæserne), men det vil ikke blive inkluderet i den kompilerede kode.

Denne compilerfejl gælder også for variabler som:

private @Nullable2 java.util.Optional<?> o;

Men kan blive acceptabel, når annotationen desuden får måltypen ElementType.FIELD , som skrevet i samme JLS-klausul:

Hvis TA yderligere er meta-annoteret med @Target(ElementType.FIELD) , derefter udtrykket @TA java.lang.Object er lovligt på steder, der er både deklarations- og typekontekster, såsom en felterklæring @TA java.lang.Object f; . Her anses @TA for at gælde for deklarationen af ​​f (og ikke for typen java.lang.Object), fordi TA er anvendelig i feltdeklarationskonteksten.


Når du bruger annoteringer, er dette den syntaks, der bruges, når du vil skrive et fuldt kvalificeret navn til typen, i stedet for at tilføje importerklæring.

Citerer fra checker framework manualen:

Den korrekte Java-syntaks til at skrive en annotering på et fuldt kvalificeret typenavn er at sætte annotationen på den simple navnedel, som [email protected] List. Men det er normalt bedre at tilføje importjava.util.List til din kildefil, så du bare kan skrive@Nullable List.

Det er også nævnt på side 2 i JSR308 specifikation, som kan downloades her. Der står:

En typeannotation vises før typens simple navn, som in@NonNull String eller [email protected] String.


Det mærkelige her er virkelig den ukendte syntaks for at anvende en ElementType.TYPE_USE -målrettet annotation.Hvis du tjekker Nullables dokumenter, vil du se det ukendte mål:

...
@Target(value={TYPE_USE,TYPE_PARAMETER})
<public @interface Nullable
...

Denne annotering bruges lige før det simple navn på den annoterede type, ligesom i begge følgende:

public static <T> @Nullable Optional<T> toJavaUtil
public static <T> [email protected] Optional<T> toJavaUtil

Jeg vidste ikke, hvad brugen af ​​denne slags mål var, så efter en hurtig læsning kom jeg til dette enkle eksempel, som henter metadata af returtype ved hjælp af en annotering, der har dette mål:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@interface InterceptedReturnValue {
    boolean value() default true;
}

Og behandlede det ved hjælp af:

public [email protected](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
        }
    }
}

Jeg er sikker på, at mange nyttige rammer, såsom checkerframework, gør den mest passende brug af ElementType.TYPE_USE


Java tag