Pravděpodobně jste se setkali se situacemi, kdy je potřeba se spojit metadata (data, která popisují další data) s třídami, metodami a / nebo jinými aplikačními prvky. Například váš programovací tým možná bude muset identifikovat nedokončené třídy ve velké aplikaci. U každé nedokončené třídy by metadata pravděpodobně obsahovala jméno vývojáře odpovědného za dokončení třídy a očekávané datum dokončení třídy.
Před Java 5 byly komentáře jediným flexibilním mechanismem, který Java musela nabídnout pro přidružení metadat k prvkům aplikace. Komentáře jsou však špatná volba. Protože je kompilátor ignoruje, komentáře nejsou za běhu k dispozici. A i kdyby byly k dispozici, musel by se text analyzovat, aby se získaly důležité datové položky. Bez standardizace způsobu zadávání datových položek by tyto datové položky mohly být analyzovány jako nemožné.
stáhnout Získat kód Stáhněte si zdrojový kód pro příklady v tomto výukovém programu Java 101. Vytvořil Jeff Friesen pro.Nestandardní anotační mechanismy
Java poskytuje nestandardní mechanismy pro přidružení metadat k prvkům aplikace. Například přechodný
vyhrazené slovo vám umožní opatřit poznámkami (přidružit data k) polím, která mají být během serializace vyloučena.
Java 5 zavedením vše změnila anotace, standardní mechanismus pro přidružení metadat k různým prvkům aplikace. Tento mechanismus se skládá ze čtyř komponent:
- An
@rozhraní
mechanismus pro deklarování typů anotací. - Typy metaznaček, které můžete použít k identifikaci prvků aplikace, na které se vztahuje typ anotace; identifikovat životnost anotace (instance typu anotace); a více.
- Podpora zpracování anotací prostřednictvím rozšíření rozhraní Java Reflection API (bude popsáno v budoucím článku), které můžete použít k objevení běhových anotací programu a zobecněný nástroj pro zpracování anotací.
- Standardní typy anotací.
Jak procházíme tímto článkem, vysvětlím, jak tyto komponenty používat.
Deklarace typů anotací pomocí @interface
Typ anotace můžete deklarovat zadáním @
symbol bezprostředně následovaný symbolem rozhraní
vyhrazené slovo a identifikátor. Například výpis 1 deklaruje jednoduchý typ anotace, který můžete použít k anotaci kódu bezpečného pro vlákna.
Výpis 1:ThreadSafe.java
public @interface ThreadSafe {}
Po deklaraci tohoto typu anotace předpřipravte před metody, které považujete za bezpečné pro vlákna, instance tohoto typu @
bezprostředně následuje název typu do záhlaví metody. Výpis 2 nabízí jednoduchý příklad, kdy hlavní()
metoda je anotována @ThreadSafe
.
Výpis 2:AnnDemo.java
(verze 1)
veřejná třída AnnDemo {@ThreadSafe public static void main (String [] args) {}}
ThreadSafe
instance neposkytují žádná metadata kromě názvu typu poznámky. Můžete však zadat metadata přidáním prvků k tomuto typu, kde živel je hlavička metody umístěná v těle typu anotace.
Kromě toho, že nemají těla kódu, podléhají prvky následujícím omezením:
- Záhlaví metody nemůže deklarovat parametry.
- Záhlaví metody nemůže poskytnout klauzuli throws.
- Návratový typ hlavičky metody musí být primitivní typ (např.
int
),řetězec java.lang
,java.lang.Class
, výčet, typ anotace nebo pole jednoho z těchto typů. Pro návratový typ nelze zadat žádný jiný typ.
Jako další příklad uvádí výpis 3 a Dělat
typ poznámky se třemi prvky, které identifikují konkrétní úlohu kódování, určují datum, kdy má být úloha dokončena, a pojmenují kodéra odpovědného za dokončení úlohy.
Výpis 3:ToDo.java
(verze 1)
public @interface ToDo {int id (); Řetězec finishDate (); String coder () výchozí "n / a"; }
Všimněte si, že každý prvek nedeklaruje žádné parametry nebo vrhá klauzuli, má legální návratový typ (int
nebo Tětiva
) a končí středníkem. Konečný prvek také odhaluje, že lze zadat výchozí návratovou hodnotu; tato hodnota je vrácena, pokud anotace nepřiřadí prvku hodnotu.
Výpis 4 použití Dělat
anotovat nedokončenou metodu třídy.
Výpis 4:AnnDemo.java
(verze 2)
public class AnnDemo {public static void main (String [] args) {String [] cities = {"New York", "Melbourne", "Peking", "Moskva", "Paříž", "Londýn"}; druh (města); } @ToDo (id = 1000, finishDate = "10.10.2019", coder = "John Doe") statické zrušení neplatnosti (objekty [] objekty) {}}
Výpis 4 přiřadí každému prvku položku metadat; například, 1000
je přiřazen id
. Na rozdíl od kodér
„ id
a dokončitDatum
prvky musí být specifikovány; jinak kompilátor nahlásí chybu. Když kodér
není přiřazena hodnota, předpokládá se její výchozí hodnota „n / a“
hodnota.
Java poskytuje speciální Řetězcová hodnota ()
prvek, který lze použít k vrácení seznamu položek metadat oddělených čárkami. Výpis 5 ukazuje tento prvek v refaktorované verzi Dělat
.
Výpis 5:ToDo.java
(verze 2)
public @interface ToDo {String value (); }
Když hodnota()
je jediný prvek typu anotace, nemusíte specifikovat hodnota
a =
operátor přiřazení při přiřazení řetězce k tomuto prvku. Výpis 6 ukazuje oba přístupy.
Výpis 6:AnnDemo.java
(verze 3)
public class AnnDemo {public static void main (String [] args) {String [] cities = {"New York", "Melbourne", "Peking", "Moskva", "Paříž", "Londýn"}; druh (města); } @ToDo (value = "1000,10 / 10/2019, John Doe") statické void řazení (Object [] objekty) {} @ToDo ("1000,10 / 10/2019, John Doe") statické booleovské vyhledávání ( Object [] objects, Object key) {return false; }}
Použití typů metaanotací - problém flexibility
Můžete anotovat typy (např. Třídy), metody, lokální proměnné a další. Tato flexibilita však může být problematická. Možná budete chtít například omezit Dělat
pouze na metody, ale nic nebrání tomu, aby byl použit k anotaci dalších prvků aplikace, jak je ukázáno v seznamu 7.
Výpis 7:AnnDemo.java
(verze 4)
@ToDo ("1000,10 / 10/2019, John Doe") veřejná třída AnnDemo {public static void main (String [] args) {@ToDo (value = "1000,10 / 10/2019, John Doe") String [] města = {"New York", "Melbourne", "Peking", "Moskva", "Paříž", "Londýn"}; druh (města); } @ToDo (value = "1000,10 / 10/2019, John Doe") statické void řazení (Object [] objekty) {} @ToDo ("1000,10 / 10/2019, John Doe") statické booleovské vyhledávání ( Object [] objects, Object key) {return false; }}
V seznamu 7, Dělat
se také používá k anotaci souboru AnnDemo
třída a města
lokální proměnná. Přítomnost těchto chybných anotací může někoho zmást při kontrole vašeho kódu nebo dokonce vašich vlastních nástrojů pro zpracování anotací. Pro časy, kdy potřebujete zúžit flexibilitu typu anotace, nabízí Java cílová
anotační typ v jeho poznámka java.lang
balík.
cílová
je meta-anotační typ - typ anotace, jehož anotace anotuje anotační typy, na rozdíl od nemetanotického typu, jehož anotace anotují aplikační prvky, jako jsou třídy a metody. Identifikuje druhy prvků aplikace, pro které je použit typ anotace. Tyto prvky jsou označeny cílová
Je Hodnota ElementValue [] ()
živel.
java.lang.annotation.ElementType
je výčet, jehož konstanty popisují aplikační prvky. Například, KONSTRUKTOR
platí pro konstruktory a PARAMETR
platí pro parametry. Seznam 8 refaktorů Seznam 5 Dělat
typ poznámky omezit pouze na metody.
Výpis 8:ToDo.java
(verze 3)
import java.lang.annotation.ElementType; import java.lang.annotation.Target; @Target ({ElementType.METHOD}) public @interface ToDo {String value (); }
Vzhledem k refaktorování Dělat
typ poznámky, pokus o kompilaci Výpisu 7 má nyní za následek následující chybovou zprávu:
AnnDemo.java:1: error: annotation type not applicable to this kind of declaration @ToDo ("1000,10 / 10/2019, John Doe") ^ AnnDemo.java:6: error: annotation type not applicable to this kind of Declaration @ToDo (value = "1000,10 / 10/2019, John Doe") ^ 2 errors
Další typy metaanotací
Java 5 představila tři další typy metaanotací, které se nacházejí v poznámka java.lang
balík:
Zadržení
označuje, jak dlouho mají být zachovány anotace s anotovaným typem. Tento typ je přidruženjava.lang.annotation.RetentionPolicy
enum deklaruje konstantyTŘÍDA
(kompilátor zaznamenává anotace do souboru třídy; virtuální stroj je neuchovává, aby šetřil paměť - výchozí zásada),RUNTIME
(kompilátor zaznamenává anotace do souboru třídy; virtuální stroj je uchovává) aZDROJ
(kompilátor zahodí anotace).Zdokumentováno
označuje, že instanceZdokumentováno
-anotované anotace mají být dokumentoványjavadoc
a podobné nástroje.Zděděno
označuje, že typ anotace je automaticky zděděn.
Java 8 představila java.lang.annotation.Repeatable
meta-anotační typ. Opakovatelný
se používá k označení, že typ anotace, jejíž deklaraci anotuje (meta-), je opakovatelný. Jinými slovy můžete na prvek aplikace použít více anotací ze stejného opakovatelného typu anotace, jak je ukázáno zde:
@ToDo (hodnota = "1000,10 / 10/2019, John Doe") @ToDo (hodnota = "1001,10 / 10/2019, Kate Doe") statické třídění void (Object [] objekty) {}
Tento příklad to předpokládá Dělat
byl anotován s Opakovatelný
typ poznámky.
Zpracování anotací
Anotace jsou určeny ke zpracování; jinak je nemá smysl mít. Java 5 rozšířila rozhraní Reflection API, aby vám pomohla vytvořit vlastní nástroje pro zpracování anotací. Například, Třída
prohlašuje Anotace [] getAnnotations ()
metoda, která vrací pole java.lang.Annotation
instance popisující anotace přítomné na prvku popsaném v Třída
objekt.
Výpis 9 představuje jednoduchou aplikaci, která načte soubor třídy a prozkoumá jeho metody Dělat
anotace a na výstupu komponenty každé nalezené anotace.
Výpis 9:AnnProcDemo.java
import java.lang.reflect.Method; public class AnnProcDemo {public static void main (String [] args) throws Exception {if (args.length! = 1) {System.err.println ("usage: java AnnProcDemo classfile"); vrátit se; } Metoda [] metody = Class.forName (args [0]). GetMethods (); for (int i = 0; i <methods.length; i ++) {if (methods [i] .isAnnotationPresent (ToDo.class)) {ToDo todo = methods [i] .getAnnotation (ToDo.class); Řetězec [] komponenty = todo.value (). Split (","); System.out.printf ("ID =% s% n", komponenty [0]); System.out.printf ("Datum dokončení =% s% n", komponenty [1]); System.out.printf ("Coder =% s% n% n", komponenty [2]); }}}}
Po ověření, že byl zadán přesně jeden argument příkazového řádku (identifikace souboru třídy), hlavní()
načte soubor třídy pomocí Class.forName ()
, vyvolá getMethods ()
vrátit pole java.lang.reflect.Method
objekty identifikující všechny veřejnost
metody v souboru třídy a tyto metody zpracovává.
Zpracování metody začíná vyvoláním Metoda
Je boolean isAnnotationPresent (Class annotationClass)
metoda k určení, zda anotace popsaná ToDo.class
je na metodě přítomen. Pokud ano, Metoda
Je T getAnnotation (Class annotationClass)
metoda je volána k získání anotace.
The Dělat
zpracovávané anotace jsou ty, jejichž typy deklarují jeden Řetězcová hodnota ()
prvek (viz Výpis 5). Protože metadata založená na řetězcích tohoto prvku jsou oddělena čárkami, je třeba je rozdělit do řady hodnot komponent. Každá ze tří hodnot komponent je poté zpřístupněna a odeslána.
Zkompilovat tento zdrojový kód (javac AnnProcDemo.java
). Před spuštěním aplikace budete potřebovat vhodný soubor třídy s @Dělat
anotace k jeho veřejnost
metody. Můžete například upravit seznam 6 AnnDemo
zdrojový kód k zahrnutí veřejnost
v jeho sort ()
a Vyhledávání()
záhlaví metody. Budete také potřebovat seznam 10 Dělat
typ poznámky, který vyžaduje RUNTIME
retenční politika.
Výpis 10:ToDo.java
(verze 4)
import java.lang.annotation.ElementType; importovat java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target ({ElementType.METHOD}) @Retention (RetentionPolicy.RUNTIME) public @interface ToDo {String value (); }
Zkompilovat upravené AnnDemo.java
a Výpis 10 a proveďte následující příkaz ke zpracování AnnDemo
Je Dělat
anotace:
java AnnProcDemo AnnDemo
Pokud vše půjde dobře, měli byste dodržovat následující výstup:
ID = 1000 Datum dokončení = 10/10/2019 Coder = John Doe ID = 1000 Datum dokončení = 10/10/2019 Coder = John Doe
Zpracování anotací pomocí apt a kompilátoru Java
Java 5 představil výstižný
nástroj pro všeobecné zpracování anotací. Migrace prostředí Java 6 výstižný
Funkčnost do své javac
nástroj kompilátoru a prostředí Java 7 je zastaralé výstižný
, který byl následně odstraněn (počínaje Java 8).
Standardní typy anotací
Spolu s cílová
, Zadržení
, Zdokumentováno
, a Zděděno
Byla představena Java 5 java.lang. zastaralé
, java.lang.Override
, a java.lang.SuppressWarnings
. Tyto tři typy anotací jsou navrženy pro použití pouze v kontextu kompilátoru, a proto jsou jejich zásady uchovávání nastaveny na ZDROJ
.