Du har sandsynligvis stødt på situationer, hvor du har brug for at associere metadata (data, der beskriver andre data) med klasser, metoder og / eller andre applikationselementer. For eksempel kan dit programmeringsteam muligvis have brug for at identificere ufærdige klasser i en stor applikation. For hver ufærdig klasse vil metadataene sandsynligvis indeholde navnet på den udvikler, der er ansvarlig for at afslutte klassen, og klassens forventede afslutningsdato.
Før Java 5 var kommentarer den eneste fleksible mekanisme, som Java havde at tilbyde for at knytte metadata til applikationselementer. Kommentarer er dog et dårligt valg. Da compileren ignorerer dem, er kommentarer ikke tilgængelige under kørsel. Og selvom de var tilgængelige, skulle teksten analyseres for at opnå vigtige dataelementer. Uden at standardisere, hvordan dataelementerne er specificeret, kan disse dataelementer vise sig umulige at parse.
download Hent koden Download kildekoden for eksempler i denne Java 101-tutorial. Oprettet af Jeff Friesen til.Ikke-standardiserede annoteringsmekanismer
Java giver ikke-standardiserede mekanismer til at forbinde metadata med applikationselementer. F.eks forbigående
reserveret ord lader dig kommentere (knytte data til) felter, der skal udelukkes under serialisering.
Java 5 ændrede alt ved at introducere kommentarer, en standardmekanisme til at forbinde metadata med forskellige applikationselementer. Denne mekanisme består af fire komponenter:
- En
@interface
mekanisme til at erklære annoteringstyper. - Meta-annotationstyper, som du kan bruge til at identificere de applikationselementer, som en annotationstype gælder for; at identificere levetiden for en kommentar (en forekomst af en annoteringstype); og mere.
- Understøttelse af annoteringsbehandling via en udvidelse til Java Reflection API (diskuteres i en fremtidig artikel), som du kan bruge til at opdage et programs runtime-annoteringer og et generaliseret værktøj til behandling af annoteringer.
- Standard annoteringstyper.
Jeg forklarer, hvordan man bruger disse komponenter, når vi arbejder os igennem denne artikel.
Erklæring om annoteringstyper med @interface
Du kan erklære en kommentortype ved at angive @
straks efterfulgt af interface
reserveret ord og en identifikator. For eksempel erklærer Listing 1 en simpel annoteringstype, som du muligvis bruger til at kommentere trådsikker kode.
Liste 1:ThreadSafe.java
public @interface ThreadSafe {}
Efter at have erklæret denne annoteringstype skal du forud for de metoder, som du anser for trådsikker, med forekomster af denne type ved at forhåndsudgive @
straks efterfulgt af typenavnet til metodens overskrifter. Liste 2 tilbyder et simpelt eksempel, hvor hoved ()
metoden er kommenteret @ThreadSafe
.
Liste 2:AnnDemo.java
(version 1)
offentlig klasse AnnDemo {@ThreadSafe offentlig statisk ugyldig hoved (String [] args) {}}
Trådsikker
forekomster leverer ingen andre metadata end navnet på annotationstypen. Du kan dog levere metadata ved at tilføje elementer til denne type, hvor en element er en metodeoverskrift placeret i annotationstypens krop.
Ud over at der ikke er kodeorganer er elementer underlagt følgende begrænsninger:
- Metodeoverskriften kan ikke erklære parametre.
- Metodeoverskriften kan ikke give en kasteklausul.
- Metodeoverskriftens returtype skal være en primitiv type (f.eks.
int
),java.lang.Streng
,java.lang.Klasse
, en enum, en annotationstype eller en matrix af en af disse typer. Ingen anden type kan angives for returtypen.
Som et andet eksempel præsenterer Listing 3 a At gøre
annotationstype med tre elementer, der identificerer et bestemt kodningsjob, specificerer datoen for, hvornår jobbet skal afsluttes, og navngiver koderen, der er ansvarlig for at udføre jobbet.
Liste 3:ToDo.java
(version 1)
offentlig @interface ToDo {int id (); String finishDate (); Strengkoder () standard "ikke relevant"; }
Bemærk, at hvert element erklærer ingen parameter (er) eller kaster-klausul, har en lovlig returtype (int
eller Snor
) og slutter med et semikolon. Endelig afslører det sidste element, at en standardreturværdi kan angives; denne værdi returneres, når en kommentar ikke tildeler en værdi til elementet.
Notering 4 anvendelser At gøre
at kommentere en ufærdig klassemetode.
Liste 4:AnnDemo.java
(version 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 ugyldig sortering (Objekt [] objekter) {}}
Liste 4 tildeler et metadataelement til hvert element; for eksempel, 1000
er tildelt id
. I modsætning til koder
, det id
og slutdato
elementer skal specificeres; Ellers rapporterer compileren en fejl. Hvornår koder
er ikke tildelt en værdi, antager den dens standard "ikke oplyst"
værdi.
Java giver en speciel Strengværdi ()
element, der kan bruges til at returnere en komma-adskilt liste over metadataelementer. Listing 5 demonstrerer dette element i en refactored version af At gøre
.
Liste 5:ToDo.java
(version 2)
offentlig @interface ToDo {strengværdi (); }
Hvornår værdi()
er det eneste element, der er en annoteringstype, skal du ikke angive værdi
og =
tildelingsoperatør ved tildeling af en streng til dette element. Liste 6 viser begge tilgange.
Liste 6:AnnDemo.java
(version 3)
public class AnnDemo {public static void main (String [] args) {String [] cities = {"New York", "Melbourne", "Beijing", "Moscow", "Paris", "London"}; sorter (byer); } @ToDo (værdi = "1000,10 / 10/2019, John Doe") statisk ugyldig sort (Objekt [] objekter) {} @ToDo ("1000,10 / 10/2019, John Doe") statisk boolsk søgning ( Objekt [] objekter, Objektnøgle) {returner falsk; }}
Brug af meta-annotationstyper - problemet med fleksibilitet
Du kan kommentere typer (f.eks. Klasser), metoder, lokale variabler og mere. Denne fleksibilitet kan dog være problematisk. For eksempel vil du måske begrænse At gøre
kun til metoder, men intet forhindrer det i at blive brugt til at kommentere andre applikationselementer, som det fremgår af liste 7.
Liste 7:AnnDemo.java
(version 4)
@ToDo ("1000,10 / 10/2019, John Doe") offentlig klasse AnnDemo {offentlig statisk ugyldig hoved (String [] args) {@ToDo (value = "1000,10 / 10/2019, John Doe") String [] byer = {"New York", "Melbourne", "Beijing", "Moskva", "Paris", "London"}; sorter (byer); } @ToDo (værdi = "1000,10 / 10/2019, John Doe") statisk ugyldig sort (Objekt [] objekter) {} @ToDo ("1000,10 / 10/2019, John Doe") statisk boolsk søgning ( Objekt [] objekter, Objektnøgle) {returner falsk; }}
I oversigt 7, At gøre
bruges også til at kommentere AnnDemo
klasse og byer
lokal variabel. Tilstedeværelsen af disse fejlagtige kommentarer kan forvirre nogen, der gennemgår din kode eller endda dine egne annoteringsbehandlingsværktøjer. For de tidspunkter, hvor du har brug for at indsnævre en annotationstypes fleksibilitet, tilbyder Java Mål
annoteringstype i dens java.lang.annotation
pakke.
Mål
er en meta-annotation type - en annotationstype, hvis annoteringer annoterer annoteringstyper i modsætning til en ikke-meta-annotationstype, hvis annoteringer kommenterer applikationselementer, såsom klasser og metoder. Det identificerer de typer applikationselementer, som en annoteringstype gælder for. Disse elementer er identificeret ved Mål
'S ElementValue [] værdi ()
element.
java.lang.annotation.ElementType
er et enum, hvis konstanter beskriver applikationselementer. For eksempel, BYGGER
gælder for konstruktører og PARAMETER
gælder for parametre. Notering 8 refaktorer Listing 5'er At gøre
annotationstype for kun at begrænse den til metoder.
Liste 8:ToDo.java
(version 3)
import java.lang.annotation.ElementType; import java.lang.annotation.Target; @Target ({ElementType.METHOD}) offentlig @interface ToDo {strengværdi (); }
I betragtning af refactored At gøre
annotationstype, et forsøg på at kompilere Listing 7 resulterer nu i følgende fejlmeddelelse:
AnnDemo.java:1: fejl: annoteringstype gælder ikke for denne form for erklæring @ToDo ("1000,10 / 10/2019, John Doe") ^ AnnDemo.java:6: fejl: annotationstype gælder ikke for denne form for erklæring @ ToDo (værdi = "1000,10 / 10/2019, John Doe") ^ 2 fejl
Yderligere meta-annoteringstyper
Java 5 introducerede yderligere tre meta-annoteringstyper, som findes i java.lang.annotation
pakke:
Tilbageholdelse
angiver, hvor længe kommentarer med den kommenterede type skal bevares. Denne type er tilknyttetjava.lang.annotation.RetentionPolicy
enum erklærer konstanterKLASSE
(kompilator registrerer bemærkninger i klassefilen; virtuel maskine gemmer dem ikke for at gemme hukommelse - standardpolitik),KØRETID
(kompilator registrerer bemærkninger i klassefilen; virtuel maskine bevarer dem), ogKILDE
(compiler kasserer annoteringer).Dokumenteret
angiver, at forekomster afDokumenteret
-annoterede kommentarer skal dokumenteres afjavadoc
og lignende værktøjer.Arvet
angiver, at en annoteringstype automatisk nedarves.
Java 8 introducerede java.lang.annotation.Gentagelig
meta-annotation type. Gentagelig
bruges til at angive, at annotationstypen, hvis erklæring den (meta-) kommenterer, kan gentages. Med andre ord kan du anvende flere annoteringer fra den samme gentagelige annoteringstype til et applikationselement, som vist her:
@ToDo (værdi = "1000,10 / 10/2019, John Doe") @ToDo (værdi = "1001,10 / 10/2019, Kate Doe") statisk ugyldig sort (Objekt [] objekter) {}
Dette eksempel antager det At gøre
er blevet kommenteret med Gentagelig
annoteringstype.
Behandler annoteringer
Kommentarer er beregnet til at blive behandlet; ellers er der ingen mening i at have dem. Java 5 udvidede Reflection API til at hjælpe dig med at oprette dine egne værktøjer til annoteringsbehandling. For eksempel, Klasse
erklærer en Annotation [] getAnnotations ()
metode, der returnerer en matrix af java.lang.Annotation
tilfælde, der beskriver kommentarer, der er til stede på det element, der er beskrevet af Klasse
objekt.
Listing 9 præsenterer et simpelt program, der indlæser en klassefil, forhører dets metoder til At gøre
annoteringer og output komponenterne i hver fundet kommentar.
Liste 9:AnnProcDemo.java
importere java.lang.reflect.Methode; public class AnnProcDemo {public static void main (String [] args) throw Exception {if (args.length! = 1) {System.err.println ("use: java AnnProcDemo classfile"); Vend tilbage; } 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 ("Slutdato =% s% n", komponenter [1]); System.out.printf ("Koder =% s% n% n", komponenter [2]); }}}}
Efter at have verificeret, at der er angivet nøjagtigt et kommandolinjeargument (identificering af en klassefil) hoved ()
indlæser klassefilen via Class.forName ()
påberåber sig getMethods ()
for at returnere en matrix af java.lang.reflect.Methode
objekter, der identificerer alle offentlig
metoder i klassefilen og behandler disse metoder.
Metodebehandling begynder med at påberåbe sig Metode
'S boolean isAnnotationPresent (Class annotationClass)
metode til at bestemme, om kommentaren beskrevet af ToDo.-klasse
er til stede på metoden. Hvis så, Metode
'S T getAnnotation (Class annotationClass)
metode kaldes for at opnå kommentaren.
Det At gøre
annoteringer, der behandles, er dem, hvis typer erklærer en enkelt Strengværdi ()
element (se liste 5). Da dette elements strengbaserede metadata er kommasepareret, skal det opdeles i en række komponentværdier. Hver af de tre komponentværdier åbnes og outputes derefter.
Kompilér denne kildekode (javac AnnProcDemo.java
). Inden du kan køre applikationen, skal du bruge en passende klassefil med @At gøre
bemærkninger om dens offentlig
metoder. For eksempel kan du ændre Listing 6'er AnnDemo
kildekode, der skal medtages offentlig
i dets sortere()
og Søg()
metodeoverskrifter. Du skal også have en liste over 10'er At gøre
annotationstype, som kræver KØRETID
fastholdelsespolitik.
Liste 10:ToDo.java
(version 4)
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target ({ElementType.METHOD}) @Retention (RetentionPolicy.RUNTIME) offentlig @interface ToDo {strengværdi (); }
Kompilér den modificerede AnnDemo.java
og Listing 10, og udfør følgende kommando for at behandle AnnDemo
'S At gøre
kommentarer:
java AnnProcDemo AnnDemo
Hvis alt går godt, skal du overholde følgende output:
ID = 1000 Slutdato = 10/10/2019 Koder = John Doe ID = 1000 Slutdato = 10/10/2019 Koder = John Doe
Behandling af kommentarer med apt og Java-kompilatoren
Java 5 introducerede en apt
værktøj til at behandle annoteringer på en generaliseret måde. Java 6 migreret apt
'S funktionalitet i sin javac
kompilatorværktøj, og Java 7 udfaset apt
, som efterfølgende blev fjernet (startende med Java 8).
Standard annoteringstyper
Sammen med Mål
, Tilbageholdelse
, Dokumenteret
og Arvet
, Java 5 introduceret java.lang. udfaset
, java.lang.Override
og java.lang.SuppressWarnings
. Disse tre annoteringstyper er designet til kun at blive brugt i en compiler-kontekst, hvorfor deres fastholdelsespolitikker er indstillet til KILDE
.