Du har sannsynligvis møtt situasjoner der du trenger å knytte deg metadata (data som beskriver andre data) med klasser, metoder og / eller andre applikasjonselementer. For eksempel kan programmeringsteamet ditt trenge å identifisere uferdige klasser i et stort program. For hver uferdige klasse vil metadataene sannsynligvis inneholde navnet på utvikleren som er ansvarlig for å fullføre klassen og klassens forventede fullføringsdato.
Før Java 5 var kommentarer den eneste fleksible mekanismen som Java hadde å tilby for å knytte metadata til applikasjonselementer. Kommentarer er imidlertid et dårlig valg. Fordi kompilatoren ignorerer dem, er kommentarer ikke tilgjengelige på kjøretid. Og selv om de var tilgjengelige, måtte teksten analyseres for å få viktige dataelementer. Uten å standardisere hvordan dataelementene er spesifisert, kan disse dataelementene vise seg umulige å analysere.
last ned Få koden Last ned kildekoden for eksempler i denne Java 101-opplæringen. Skapt av Jeff Friesen for.Ikke-standardiseringsmekanismer
Java gir ikke-standardiserte mekanismer for å knytte metadata til applikasjonselementer. For eksempel flyktig
reservert ord lar deg kommentere (knytte data til) felt som skal ekskluderes under serialisering.
Java 5 endret alt ved å introdusere kommentarer, en standardmekanisme for å knytte metadata til forskjellige applikasjonselementer. Denne mekanismen består av fire komponenter:
- An
@grensesnitt
mekanisme for å erklære merkingstyper. - Meta-annoteringstyper, som du kan bruke til å identifisere applikasjonselementene som en merkingstype gjelder for; for å identifisere levetiden til en kommentar (en forekomst av en merknadstype); og mer.
- Støtte for behandling av merknader via en utvidelse til Java Reflection API (som skal diskuteres i en fremtidig artikkel), som du kan bruke til å oppdage programets kjøretidskommentarer, og et generelt verktøy for behandling av merknader.
- Standard merketyper.
Jeg forklarer hvordan du bruker disse komponentene når vi arbeider oss gjennom denne artikkelen.
Erklærer merketyper med @interface
Du kan erklære en merknadstype ved å spesifisere @
symbol umiddelbart etterfulgt av grensesnitt
reservert ord og en identifikator. For eksempel erklærer Oppføring 1 en enkel merketype som du kan bruke til å kommentere trådsikker kode.
Oppføring 1:ThreadSafe.java
public @interface ThreadSafe {}
Etter å ha erklært denne merketypen, må du prefiksere metodene du anser som trådsikre med forekomster av denne typen @
umiddelbart etterfulgt av typenavnet til metodens overskrifter. Oppføring 2 gir et enkelt eksempel der hoved()
metoden er kommentert @ThreadSafe
.
Oppføring 2:AnnDemo.java
(versjon 1)
offentlig klasse AnnDemo {@ThreadSafe public static void main (String [] args) {}}
ThreadSafe
forekomster gir ingen andre metadata enn navnet på merketypen. Du kan imidlertid levere metadata ved å legge til elementer i denne typen, der en element er en metodehode plassert i kroppen for merknaden.
I tillegg til å ikke ha kodelapper, er elementer underlagt følgende begrensninger:
- Metodeoverskriften kan ikke erklære parametere.
- Metodeoverskriften kan ikke gi kaste-klausul.
- Metodeoverskriftens returtype må være en primitiv type (f.eks.
int
),java.lang.Streng
,java.lang.Klasse
, en enum, en merknadstype eller en matrise av en av disse typene. Ingen annen type kan spesifiseres for returtypen.
Som et annet eksempel presenterer Listing 3 a Å gjøre
merketype med tre elementer som identifiserer en bestemt kodejobb, spesifiserer datoen når jobben skal avsluttes, og navngir koderen som er ansvarlig for å fullføre jobben.
Oppføring 3:ToDo.java
(versjon 1)
offentlig @interface ToDo {int id (); String finishDate (); Strengkoder () er standard "ikke relevant"; }
Merk at hvert element erklærer ingen parameter (er) eller kaste-klausul, har en lovlig returtype (int
eller String
), og avsluttes med semikolon. Det siste elementet avslører også at en standard returverdi kan spesifiseres; denne verdien returneres når en kommentar ikke tilordner elementet en verdi.
Oppføring 4 bruker Å gjøre
å kommentere en uferdig klassemetode.
Oppføring 4:AnnDemo.java
(versjon 2)
public class AnnDemo {public static void main (String [] args) {String [] cities = {"New York", "Melbourne", "Beijing", "Moscow", "Paris", "London"}; sorter (byer); } @ToDo (id = 1000, finishDate = "10/10/2019", coder = "John Doe") statisk tomt sortering (Objekt [] objekter) {}}
Oppføring 4 tilordner et metadataelement til hvert element; for eksempel, 1000
er tildelt id
. I motsetning til koder
, den id
og sluttdato
elementer må spesifiseres; Ellers rapporterer kompilatoren en feil. Når koder
ikke er tildelt en verdi, antar den standardverdien "ikke tilgjengelig"
verdi.
Java gir en spesiell Strengverdi()
element som kan brukes til å returnere en kommaseparert liste over metadataelementer. Oppføring 5 demonstrerer dette elementet i en ombygd versjon av Å gjøre
.
Oppføring 5:ToDo.java
(versjon 2)
public @interface ToDo {Strengverdi (); }
Når verdi()
er det eneste elementet for en merknadstype, du trenger ikke å spesifisere verdi
og =
oppdragsoperatør når du tilordner en streng til dette elementet. Oppføring 6 viser begge tilnærminger.
Oppføring 6:AnnDemo.java
(versjon 3)
public class AnnDemo {public static void main (String [] args) {String [] cities = {"New York", "Melbourne", "Beijing", "Moscow", "Paris", "London"}; sorter (byer); } @ToDo (value = "1000,10 / 10/2019, John Doe") statisk ugyldig sort (Objekt [] objekter) {} @ToDo ("1000,10 / 10/2019, John Doe") statisk boolsk søk ( Object [] objects, Object key) {return false; }}
Bruke meta-merknader - problemet med fleksibilitet
Du kan kommentere typer (f.eks. Klasser), metoder, lokale variabler og mer. Denne fleksibiliteten kan imidlertid være problematisk. Det kan for eksempel være lurt å begrense Å gjøre
bare til metoder, men ingenting hindrer at den brukes til å kommentere andre applikasjonselementer, som vist i Listing 7.
Oppføring 7:AnnDemo.java
(versjon 4)
@ToDo ("1000,10 / 10/2019, John Doe") offentlig klasse AnnDemo {public static void main (String [] args) {@ToDo (value = "1000,10 / 10/2019, John Doe") String [] cities = {"New York", "Melbourne", "Beijing", "Moscow", "Paris", "London"}; sorter (byer); } @ToDo (value = "1000,10 / 10/2019, John Doe") statisk ugyldig sort (Objekt [] objekter) {} @ToDo ("1000,10 / 10/2019, John Doe") statisk boolsk søk ( Object [] objects, Object key) {return false; }}
I oppføring 7, Å gjøre
brukes også til å kommentere AnnDemo
klasse og byer
lokal variabel. Tilstedeværelsen av disse feilaktige merknadene kan forvirre noen som vurderer koden din, eller til og med dine egne verktøy for behandling av merknader. For de gangene du trenger å begrense fleksibiliteten til en merketype, tilbyr Java Mål
merketype i sin java.lang.annotasjon
pakke.
Mål
er en meta-merknadstype - en merketype hvis merknader kommenterer merketyper, i motsetning til en ikke-metatilkoblingstype hvis merknader kommenterer applikasjonselementer, for eksempel klasser og metoder. Den identifiserer hvilke applikasjonselementer som en merknadstype gjelder for. Disse elementene er identifisert av Mål
’S ElementValue [] verdi ()
element.
java.lang.annotation.ElementType
er et enum der konstanter beskriver applikasjonselementer. For eksempel, BYGGER
gjelder for konstruktører og PARAMETER
gjelder parametere. Listing 8 refactors Listing 5’s Å gjøre
merketype for å begrense den til kun metoder.
Oppføring 8:ToDo.java
(versjon 3)
importere java.lang.annotation.ElementType; importere java.lang.annotation.Target; @Target ({ElementType.METHOD}) offentlig @interface ToDo {strengverdi (); }
Gitt refactored Å gjøre
merknadstype, et forsøk på å kompilere oppføring 7 resulterer nå i følgende feilmelding:
AnnDemo.java:1: feil: merknadstype gjelder ikke for denne typen erklæring @ToDo ("1000,10 / 10/2019, John Doe") ^ AnnDemo.java:6: feil: merknadstype gjelder ikke for denne typen erklæring @ToDo (verdi = "1000,10 / 10/2019, John Doe") ^ 2 feil
Flere meta-merknader typer
Java 5 introduserte tre ekstra meta-annoteringstyper, som finnes i java.lang.annotasjon
pakke:
Bevaring
angir hvor lange kommentarer med den merkede typen skal beholdes. Denne typen er tilknyttetjava.lang.annotation.RetentionPolicy
enum erklærer konstanterKLASSE
(kompilator registrerer merknader i klassefilen; virtuell maskin beholder dem ikke for å spare minne - standard policy),RUNTIME
(kompilator registrerer merknader i klassefilen; virtuell maskin beholder dem), ogKILDE
(kompilator forkaster merknader).Dokumentert
indikerer at forekomster avDokumentert
-kommenterte merknader skal dokumenteres avjavadoc
og lignende verktøy.Arvet
indikerer at en merknadstype arves automatisk.
Java 8 introduserte java.lang.annotation.Repeatable
meta-merknadstype. Gjentas
brukes til å indikere at merketypen hvis erklæring den (meta-) kommenterer, kan repeteres. Med andre ord, du kan bruke flere kommentarer fra samme repeterbare merknadstype til et applikasjonselement, som vist her:
@ToDo (value = "1000,10 / 10/2019, John Doe") @ToDo (value = "1001,10 / 10/2019, Kate Doe") statisk ugyldig sort (Objekt [] objekter) {}
Dette eksemplet forutsetter det Å gjøre
har blitt kommentert med Gjentas
merknadstype.
Behandler merknader
Kommentarer er ment å bli behandlet; ellers er det ingen vits i å ha dem. Java 5 utvidet Reflection API for å hjelpe deg med å lage dine egne verktøy for behandling av merknader. For eksempel, Klasse
erklærer en Kommentar [] getAnnotations ()
metode som returnerer en rekke java.lang.Annotasjon
tilfeller som beskriver merknader til stede på elementet beskrevet av Klasse
gjenstand.
Listing 9 presenterer et enkelt program som laster inn en klassefil, avhører metodene for Å gjøre
merknader, og skriver ut komponentene i hver funnet kommentar.
Oppføring 9:AnnProcDemo.java
importere java.lang.reflect.Method; offentlig klasse AnnProcDemo {offentlig statisk ugyldig hoved (String [] args) kaster Unntak {if (args.length! = 1) {System.err.println ("bruk: java AnnProcDemo classfile"); komme tilbake; } Metode [] metoder = Class.forName (args [0]). GetMethods (); for (int i = 0; i <methods.length; i ++) {if (metoder [i] .isAnnotationPresent (ToDo.class)) {ToDo todo = metoder [i] .getAnnotation (ToDo.class); Streng [] komponenter = todo.value (). Split (","); System.out.printf ("ID =% s% n", komponenter [0]); System.out.printf ("Sluttdato =% s% n", komponenter [1]); System.out.printf ("Koder =% s% n% n", komponenter [2]); }}}}
Etter å ha bekreftet at nøyaktig ett kommandolinjeargument (identifisering av en klassefil) er spesifisert, hoved()
laster klassefilen via Class.forName ()
, påkaller getMethods ()
for å returnere en rekke java.lang.reflect.Methode
objekter som identifiserer alle offentlig
metoder i klassefilen, og behandler disse metodene.
Metodebehandling begynner med å påkalle Metode
’S boolean isAnnotationPresent (Class annotationClass)
metode for å avgjøre om merknaden beskrevet av ToDo.klasse
er tilstede på metoden. I så fall, Metode
’S T getAnnotation (Class annotationClass)
metoden kalles for å få merknaden.
De Å gjøre
merknader som behandles er de hvis typer erklærer en singel Strengverdi()
element (se oppføring 5). Fordi dette elementets strengbaserte metadata er kommaseparert, må det deles inn i en rekke komponentverdier. Hver av de tre komponentverdiene blir deretter åpnet og sendt ut.
Kompiler denne kildekoden (javac AnnProcDemo.java
). Før du kan kjøre applikasjonen, trenger du en passende klassefil med @Å gjøre
merknader om det offentlig
metoder. For eksempel kan du endre Listing 6’s AnnDemo
kildekode som skal inkluderes offentlig
i sin sortere()
og Søk()
metodeoverskrifter. Du trenger også oppføring 10-tallet Å gjøre
merketype, som krever RUNTIME
oppbevaringspolitikk.
Oppføring 10:ToDo.java
(versjon 4)
importere java.lang.annotation.ElementType; importere java.lang.annotation.Retention; importere java.lang.annotation.RetentionPolicy; importere java.lang.annotation.Target; @Target ({ElementType.METHOD}) @Retention (RetentionPolicy.RUNTIME) public @interface ToDo {Strengverdi (); }
Kompiler den modifiserte AnnDemo.java
og Listing 10, og utfør følgende kommando for å behandle AnnDemo
’S Å gjøre
kommentarer:
java AnnProcDemo AnnDemo
Hvis alt går bra, bør du følge følgende utdata:
ID = 1000 sluttdato = 10.10.2019 Koder = John Doe ID = 1000 sluttdato = 10.10.2019 Koder = John Doe
Behandler merknader med apt og Java-kompilatoren
Java 5 introduserte en apt
verktøy for å behandle merknader på en generalisert måte. Java 6 migrerte apt
Funksjonalitet i sin javac
kompilatorverktøy, og Java 7 avviklet apt
, som deretter ble fjernet (startende med Java 8).
Standard merketyper
Sammen med Mål
, Bevaring
, Dokumentert
, og Arvet
, Introduserte Java 5 java.lang. utdatert
, java.lang.Override
, og java.lang.SuppressWarnings
. Disse tre merketypene er designet for kun å brukes i en kompilatorkontekst, og det er derfor deres retensjonspolitikk er satt til KILDE
.