Ohjelmointi

Kuinka kuvata Java-koodia merkinnöillä

Olet todennäköisesti kohdannut tilanteita, joissa sinun täytyy olla tekemisissä metatiedot (data, joka kuvaa muita tietoja) luokkiin, menetelmiin ja / tai muihin sovelluselementteihin. Esimerkiksi ohjelmointitiimisi saattaa joutua tunnistamaan keskeneräiset luokat isossa sovelluksessa. Jokaisen keskeneräisen luokan metatietoihin sisältyisi todennäköisesti luokan viimeistelystä vastaavan kehittäjän nimi ja luokan odotettu valmistumispäivä.

Ennen Java 5: ää kommentit olivat ainoa joustava mekanismi, jonka Java oli tarjonnut metatietojen yhdistämiseksi sovelluselementteihin. Kommentit ovat kuitenkin huono valinta. Koska kääntäjä ohittaa ne, kommentit eivät ole käytettävissä ajon aikana. Ja vaikka niitä olisi saatavilla, teksti olisi jäsenneltävä tärkeiden tietoerien saamiseksi. Ilman standardoimista, miten tietoerät määritetään, näiden tietojen alkaminen voi osoittautua mahdottomaksi jäsentää.

lataa Hanki koodi Lataa lähdekoodi esimerkkejä tästä Java 101 -oppaasta. Tekijä: Jeff Friesen.

Epätyypilliset merkintämekanismit

Java tarjoaa epätyypilliset mekanismit metatietojen liittämiseksi sovelluselementteihin. Esimerkiksi ohimenevä varattu sana antaa sinun kommentoida (yhdistää tiedot) kenttiin, jotka on suljettava pois sarjoituksen aikana.

Java 5 muutti kaiken esittelemällä merkinnät, vakiomekanismi metatietojen liittämiseksi erilaisiin sovelluselementteihin. Tämä mekanismi koostuu neljästä osasta:

  • An @käyttöliittymä mekanismi merkintätyyppien ilmoittamiseksi.
  • Sisällönmerkintätyypit, joiden avulla voit tunnistaa sovelluselementit, joihin merkintätyyppi liittyy; tunnistaa merkintä (merkintätyyppinen instanssi); ja enemmän.
  • Tuki merkintöjen käsittelylle Java Reflection -sovellusliittymän laajennuksen kautta (josta keskustellaan tulevassa artikkelissa), jonka avulla voit löytää ohjelman ajonaikaiset merkinnät, ja yleistyneen työkalun merkintöjen käsittelyyn.
  • Vakiomerkintätyypit.

Selitän kuinka käyttää näitä komponentteja työskennellessämme läpi tämän artikkelin.

Merkintätyyppien ilmoittaminen @interface

Voit ilmoittaa merkintätyypin määrittämällä @ -symboli, jota seuraa välittömästi käyttöliittymä varattu sana ja tunniste. Esimerkiksi Listaus 1 ilmoittaa yksinkertaisen merkintätyypin, jota voit käyttää merkitsemään säikeetöntä koodia.

Listaus 1:ThreadSafe.java

public @interface ThreadSafe {}

Kun olet ilmoittanut tämän merkintätyypin, etuliitä menetelmät, joita pidät ketjun turvallisina, tämän tyyppisiin ilmentymiin valmistelemalla @ seuraa välittömästi tyypin nimi metodin otsikoihin. Listaus 2 tarjoaa yksinkertaisen esimerkin, jossa main () menetelmä on merkitty @ThreadSafe.

Listaus 2:AnnDemo.java (versio 1)

public class AnnDemo {@ThreadSafe public static void main (String [] argumentti) {}}

ThreadSafe esiintymät eivät tarjoa muuta metatietoa kuin merkintätyypin nimi. Voit kuitenkin toimittaa metatietoja lisäämällä elementtejä tähän tyyppiin, jossa elementti on menetelmäotsikko, joka sijoitetaan merkintätyypin runkoon.

Sen lisäksi, että elementeillä ei ole koodirunkoja, niihin sovelletaan seuraavia rajoituksia:

  • Metodin otsikko ei voi ilmoittaa parametreja.
  • Metodin otsikko ei voi antaa heittolauseketta.
  • Method-otsikon palautustyypin on oltava primitiivinen tyyppi (esim. int), java.lang.String, java.lang.luokka, luettelo, merkintätyyppi tai joukko näistä tyypeistä. Palautustyypille ei voida määrittää muuta tyyppiä.

Toisena esimerkkinä Listing 3 esittää a Tehdä merkintätyyppi, jossa on kolme elementtiä, jotka tunnistavat tietyn koodaustyön, määrittelevät päivämäärän, jolloin työ on valmis, ja nimetään työn suorittamisesta vastaava kooderi.

Listaus 3:Tehtävä.java (versio 1)

public @interface ToDo {int id (); Merkkijono viimeistelyPäiväys (); Merkkijonokooderi () oletus "ei ole"; }

Huomaa, että jokainen elementti ei ilmoita parametreja tai heittolausekkeita, sillä on laillinen palautustyyppi (int tai Merkkijono) ja päättyy puolipisteeseen. Viimeinen elementti paljastaa myös, että oletuspalautusarvo voidaan määrittää; tämä arvo palautetaan, kun merkinnällä ei määritetä arvoa elementille.

Luettelossa 4 käyttötarkoitusta Tehdä merkitsemään keskeneräinen luokan menetelmä.

Listaus 4:AnnDemo.java (versio 2)

julkinen luokka AnnDemo {public static void main (String [] args) {String [] kaupungit = {"New York", "Melbourne", "Beijing", "Moscow", "Paris", "London"}; lajitella (kaupungit); } @ToDo (id = 1000, finishDate = "10.10.2019", kooderi = "John Doe") staattinen void sort (Object [] objektit) {}}

Listaus 4 määrittää metadata-kohteen kullekin elementille; esimerkiksi, 1000 on osoitettu id. Toisin kuin kooderi, id ja finishDate elementit on määriteltävä; muuten kääntäjä ilmoittaa virheestä. Kun kooderi sille ei ole määritetty arvoa, se olettaa oletusarvon "ei käytettävissä" arvo.

Java tarjoaa erityisen Merkkijonoarvo () elementti, jota voidaan käyttää palauttamaan pilkulla erotettu metatieto-luettelo. Listaus 5 osoittaa tämän elementin uudistetussa versiossa Tehdä.

Listaus 5:Tehtävä.java (versio 2)

public @interface ToDo {Merkkijonoarvo (); }

Kun arvo() on merkintätyypin ainoa elementti, sinun ei tarvitse määrittää sitä arvo ja = määritysoperaattori määritettäessä merkkijono tälle elementille. Listaus 6 osoittaa molemmat lähestymistavat.

Listaus 6:AnnDemo.java (versio 3)

julkinen luokka AnnDemo {public static void main (String [] args) {String [] kaupungit = {"New York", "Melbourne", "Beijing", "Moscow", "Paris", "London"}; lajitella (kaupungit); } @ToDo (arvo = "1000,10 / 10/2019, John Doe") staattinen void sort (Object [] -objektit) {} @ToDo ("1000,10 / 10/2019, John Doe") staattinen looginen haku ( Object [] objektit, Object key) {return false; }}

Meta-merkintätyyppien käyttö - joustavuuden ongelma

Voit merkitä tyypit (esim. Luokat), menetelmät, paikalliset muuttujat ja paljon muuta. Tämä joustavuus voi kuitenkin olla ongelmallista. Voit esimerkiksi haluta rajoittaa Tehdä vain menetelmiin, mutta mikään ei estä sitä käyttämästä muiden sovelluselementtien merkitsemistä, kuten Listing 7 osoittaa.

Listaus 7:AnnDemo.java (versio 4)

@ToDo ("1000,10 / 10/2019, John Doe") julkisen luokan AnnDemo {public static void main (String [] args) {@ToDo (value = "1000,10 / 10/2019, John Doe") String [] kaupungit = {"New York", "Melbourne", "Beijing", "Moskova", "Pariisi", "Lontoo"}; lajitella (kaupungit); } @ToDo (arvo = "1000,10 / 10/2019, John Doe") staattinen void sort (Object [] -objektit) {} @ToDo ("1000,10 / 10/2019, John Doe") staattinen looginen haku ( Object [] objektit, Object key) {return false; }}

Luettelossa 7, Tehdä käytetään myös merkitsemään AnnDemo luokka ja kaupungeissa paikallinen muuttuja. Näiden virheellisten merkintöjen läsnäolo saattaa hämmentää koodiasi tarkistavan henkilön tai jopa omat merkintöjen käsittelytyökalusi. Jos haluat pienentää merkintätyypin joustavuutta, Java tarjoaa Kohde merkintätyyppi sen java.lang.merkintä paketti.

Kohde on meta-merkintätyyppi - merkintätyyppi, jonka merkinnät merkitsevät merkintätyyppejä, toisin kuin ei-meta-merkintätyyppi, jonka merkinnät merkitsevät sovelluselementtejä, kuten luokkia ja menetelmiä. Se tunnistaa sovelluksen elementtityypit, joihin merkintätyyppiä sovelletaan. Nämä elementit tunnistetaan KohdeS ElementValue [] -arvo () elementti.

java.lang.annotation.ElementType on enum, jonka vakiot kuvaavat sovelluselementtejä. Esimerkiksi, RAKENTAJA koskee rakentajia ja PARAMETRI koskee parametreja. Listing 8 refactors Listing 5's Tehdä merkintätyyppi rajoittaa sen vain menetelmiin.

Listaus 8:Tehtävä.java (versio 3)

tuo java.lang.annotation.ElementType; tuo java.lang.annotation.Target; @Target ({ElementType.METHOD}) public @interface ToDo {String value (); }

Ottaen huomioon uudistetun Tehdä merkintätyyppi, yritys luoda luettelo 7 johtaa nyt seuraavaan virheilmoitukseen:

AnnDemo.java:1: virhe: merkintätyyppi ei koske tämän tyyppistä ilmoitusta @ToDo ("1000,10 / 10/2019, John Doe") ^ AnnDemo.java:6: virhe: merkintätyyppi ei koske tällaista ilmoitus @ToDo (arvo = "1000,10 / 10/2019, John Doe") ^ 2 virhettä

Muita meta-merkintätyyppejä

Java 5 esitteli kolme muuta meta-merkintätyyppiä, jotka löytyvät java.lang.merkintä paketti:

  • Säilytys ilmaisee kuinka kauan annotoidun tyyppisiä merkintöjä säilytetään. Tähän tyyppiin liittyy java.lang.annotation.RetentionPolicy enum julistaa vakiot LUOKKA (kääntäjä tallentaa merkinnät luokkatiedostoon; virtuaalikone ei pidä niitä muistin säästämiseksi - oletuskäytäntö), RUNTIME (kääntäjä tallentaa merkinnät luokkatiedostoon; virtuaalikone säilyttää ne), ja LÄHDE (kääntäjä hylkää merkinnät).
  • Dokumentoitu osoittaa, että Dokumentoitu- merkitsemättömät merkinnät on dokumentoitava javadoc ja vastaavia työkaluja.
  • Peritty ilmaisee, että merkintätyyppi peritään automaattisesti.

Java 8 esitteli java.lang.annotation.Muistettavissa meta-merkintätyyppi. Toistettavissa käytetään osoittamaan, että merkintätyyppi, jonka ilmoituksen se (meta-) merkitsee, on toistettavissa. Toisin sanoen voit soveltaa useita merkintöjä samasta toistettavasta merkintätyypistä sovelluselementtiin, kuten tässä osoitetaan:

@ToDo (arvo = "1000,10 / 10/2019, John Doe") @ToDo (arvo = "1001,10 / 10/2019, Kate Doe") staattinen void sort (Object [] -objektit) {}

Tässä esimerkissä oletetaan, että Tehdä on merkitty Toistettavissa merkinnän tyyppi.

Käsitellään merkintöjä

Merkinnät on tarkoitettu käsiteltäviksi; muuten ei ole mitään järkeä pitää niitä. Java 5 laajensi Reflection-sovellusliittymää auttamaan sinua luomaan omia merkintöjen käsittelytyökaluja. Esimerkiksi, Luokka julistaa Merkintä [] getAnnotations () menetelmä, joka palauttaa taulukon java.lang. huomautus esimerkit, jotka kuvaavat merkintöjä, jotka esiintyvät Luokka esine.

Listaus 9 esittää yksinkertaisen sovelluksen, joka lataa luokkatiedoston, kyselee sen menetelmiä Tehdä merkinnät ja tuottaa kunkin löydetyn merkinnän komponentit.

Listaus 9:AnnProcDemo.java

tuo java.lang.reflect.Method; public class AnnProcDemo {public static void main (String [] args) heittää poikkeuksen {if (args.pituus! = 1) {System.err.println ("käyttö: java AnnProcDemo classfile"); palata; } Method [] metodit = Class.forName (argumentit [0]). GetMethods (); for (int i = 0; i <method.length; i ++) {if (method [i] .isAnnotationPresent (ToDo.class)) {ToDo todo = metodit [i] .getAnnotation (ToDo.class); Merkkijono [] komponentit = todellinen.arvo (). Split (","); System.out.printf ("ID =% s% n", komponentit [0]); System.out.printf ("Viimeinen päivä =% s% n", komponentit [1]); System.out.printf ("kooderi =% s% n% n", komponentit [2]); }}}}

Kun olet varmistanut, että täsmälleen yksi komentoriviargumentti (luokkatiedoston tunnistaminen) on määritetty, main () lataa luokkatiedoston kautta Class.forName (), vetoaa getMethods () palauttaa joukko java.lang.reflect.Method kaikki tunnistavat objektit julkinen menetelmät luokkatiedostossa ja käsittelee nämä menetelmät.

Menetelmän käsittely alkaa vetoamalla MenetelmäS looginen isAnnotationPresent (luokan annotationClass) menetelmä sen määrittämiseksi, onko Tehtävä.luokka on läsnä menetelmässä. Jos niin, MenetelmäS T getAnnotation (luokan annotationClass) menetelmää kutsutaan merkinnän saamiseksi.

Tehdä Käsiteltyjä merkintöjä ovat ne, joiden tyypit ilmoittavat yhden Merkkijonoarvo () elementti (katso luettelo 5). Koska tämän elementin merkkijonopohjaiset metatiedot on erotettu pilkuilla, se on jaettava komponenttiarvojen ryhmäksi. Kumpaankin kolmesta komponenttiarvosta pääsee sitten käsiksi ja tulostetaan.

Käännä tämä lähdekoodi (javac AnnProcDemo.java). Ennen kuin voit käyttää sovellusta, tarvitset sopivan luokkatiedoston @Tehdä sen merkinnät julkinen menetelmiä. Voit esimerkiksi muokata luetteloa 6 AnnDemo lisättävä lähdekoodi julkinen sen järjestellä() ja Hae() menetelmän otsikot. Tarvitset myös Listaus 10: n Tehdä merkintätyyppi, joka vaatii RUNTIME säilyttämispolitiikka.

Listaus 10:Tehtävä.java (versio 4)

tuo java.lang.annotation.ElementType; tuo java.lang.annotation.Retention; tuo java.lang.annotation.RetentionPolicy; tuo java.lang.annotation.Target; @Target ({ElementType.METHOD}) @Retention (RetentionPolicy.RUNTIME) public @interface ToDo {String value (); }

Koosta muokattu AnnDemo.java ja Listaus 10, ja suorita seuraava komento käsiteltäväksi AnnDemoS Tehdä merkinnät:

java AnnProcDemo AnnDemo

Jos kaikki menee hyvin, sinun on noudatettava seuraavaa tulosta:

ID = 1000 Viimeistelypäivä = 10.10.2019 Coder = John Doe ID = 1000 Viimeistelypäivä = 10.10.2019 Coder = John Doe

Käsitellään merkintöjä apt: llä ja Java-kääntäjällä

Java 5 esitteli apt työkalu merkintöjen yleiseen käsittelyyn. Java 6 siirtyi aptToiminnallisuutta javac kääntäjä ja Java 7 vanhentuneet apt, joka myöhemmin poistettiin (alkaen Java 8: sta).

Vakiomerkintätyypit

Kera Kohde, Säilytys, Dokumentoituja Peritty, Java 5 esiteltiin java.lang. vanhentunut, java.lang.Ohitaja java.lang.SuppressWarnings. Nämä kolme merkintätyyppiä on suunniteltu käytettäväksi vain kääntäjän yhteydessä, minkä vuoksi niiden säilytyskäytännöiksi on asetettu LÄHDE.

Vanhentunut