Overzicht van ingebouwde aantekeningen in Java
1. Overzicht
In dit artikel zullen we het hebben over een kernfunctie van de Java-taal: de standaardannotaties die beschikbaar zijn in de JDK.
2. Wat een aantekening is
Simpel gezegd, annotaties zijn dat wel Java-typen die worden voorafgegaan door een "@" -symbool.
Java heeft annotaties sinds de 1.5-release. Sindsdien hebben ze vorm gegeven aan de manier waarop we onze applicaties hebben ontworpen.
Spring en Hibernate zijn geweldige voorbeelden van frameworks die sterk afhankelijk zijn van annotaties om verschillende ontwerptechnieken mogelijk te maken.
Eigenlijk, een annotatie wijst extra metadata toe aan de broncode waaraan het is gebonden. Door een annotatie toe te voegen aan een methode, interface, klasse of veld, kunnen we:
- Informeer de compiler over waarschuwingen en fouten
- Manipuleer de broncode tijdens het compileren
- Wijzig of onderzoek het gedrag tijdens runtime
3. Ingebouwde aantekeningen in Java
Nu we de basis hebben besproken, gaan we eens kijken naar enkele annotaties die worden geleverd met kern Java. Ten eerste zijn er verschillende die de compilatie informeren:
- @Override
- @SuppressWarnings
- @Verouderd
- @BuienRadarNL
- @FunctioneleInterface
- @Native
Deze annotaties genereren of onderdrukken compilerwaarschuwingen en fouten. Ze consequent toepassen is vaak een goede gewoonte, omdat het toevoegen ervan toekomstige programmeerfouten kan voorkomen.
De @Override annotatie wordt gebruikt om aan te geven dat een methode het gedrag van een overgeërfde methode overschrijft of vervangt.
@SuppressWarnings geeft aan dat we bepaalde waarschuwingen van een deel van de code willen negeren. De @BuienRadarNL annotatie werkt ook op een soort waarschuwing met betrekking tot het gebruik van varargs.
De @Verouderd annotatie kan worden gebruikt om een API te markeren als niet meer bedoeld voor gebruik. Bovendien is deze annotatie achteraf aangebracht in Java 9 om meer informatie over de deprecatie weer te geven.
Voor al deze kunt u meer gedetailleerde informatie vinden in de gekoppelde artikelen.
3.1. @FunctioneleInterface
Met Java 8 kunnen we code op een meer functionele manier schrijven.
Single Abstract Method-interfaces maken hier een groot deel van uit. Als we van plan zijn een SAM-interface te gebruiken door lambda's, kunnen we deze optioneel als zodanig markeren met @FunctioneleInterface:
@FunctionalInterface openbare interface Adder {int add (int a, int b); }
Leuk vinden @Override met methoden, @FunctioneleInterface verklaart onze bedoelingen met Adder.
Nu, of we gebruiken @FunctioneleInterface of niet, we kunnen nog steeds gebruiken Adder op dezelfde manier:
Opteller opteller = (a, b) -> a + b; int resultaat = adder.add (4,5);
Maar als we een tweede methode toevoegen aan Adder, dan zal de compiler klagen:
@FunctionalInterface public interface Adder {// compiler klaagt dat de interface geen SAM int add (int a, int b) is; int div (int a, int b); }
Nu, dit zou zijn gecompileerd zonder de @FunctioneleInterface annotatie. Dus, wat levert het ons op?
Leuk vinden @Override, deze annotatie beschermt ons tegen toekomstige programmeerfouten. Ook al is het legaal om meer dan één methode op een interface te hebben, het is niet wanneer die interface wordt gebruikt als een lambda-doel. Zonder deze annotatie zou de compiler breken op de tientallen plaatsen waar Adder werd gebruikt als lambda. Nu, het breekt gewoon in Adder zelf.
3.2. @Native
Vanaf Java 8 is er een nieuwe annotatie in het java.lang.annotation pakket genaamd Inheems. De @Native annotatie is alleen van toepassing op velden. Het geeft aan dat het geannoteerde veld een constante is waarnaar kan worden verwezen vanuit de oorspronkelijke code. Hier is bijvoorbeeld hoe het wordt gebruikt in de Geheel getal klasse:
public final class Geheel getal {@Native public static final int MIN_VALUE = 0x80000000; // weggelaten}
Deze annotatie kan ook dienen als een hint voor de tools om enkele extra header-bestanden te genereren.
4. Meta-annotaties
Vervolgens zijn meta-annotaties annotaties die op andere annotaties kunnen worden toegepast.
Deze meta-annotaties worden bijvoorbeeld gebruikt voor het configureren van annotaties:
- @Doelwit
- @Retentie
- @Geërfd
- @Documented
- @Repeatable
4.1. @Doelwit
Het bereik van annotaties kan variëren op basis van de vereisten. Hoewel één annotatie alleen met methoden wordt gebruikt, kan een andere annotatie worden gebruikt met constructor- en veldverklaringen.
Om de doelelementen van een aangepaste annotatie te bepalen, moeten we deze labelen met een @Doelwit annotatie.
@Doelwit kan werken met acht verschillende elementtypes. Als we kijken naar de broncode van @SafeVargs, dan kunnen we zien dat het alleen moet worden gekoppeld aan constructors of methoden:
@Documented @Retention (RetentionPolicy.RUNTIME) @Target ({ElementType.CONSTRUCTOR, ElementType.METHOD}) openbaar @interface SafeVarargs {}
4.2. @Retentie
Sommige annotaties zijn bedoeld als hints voor de compiler, terwijl andere tijdens runtime worden gebruikt.
Wij gebruiken de @Retentie annotatie om aan te geven waar in de levenscyclus van ons programma onze annotatie van toepassing is.
Om dit te doen, moeten we configureren @Retentie met een van de drie bewaarbeleidslijnen:
- Retentiebeleid BRON - zichtbaar door noch de compiler, noch de runtime
- RetentionPolicy.CLASS - zichtbaar voor de compiler
- RetentionPolicy.RUNTIME - zichtbaar door de compiler en de runtime
@Retentie standaard ingesteld op Retentiebeleid BRON.
Als we een annotatie hebben die tijdens runtime toegankelijk moet zijn:
@Retention (RetentionPolicy.RUNTIME) @Target (TYPE) openbaar @interface RetentionAnnotation {}
Als we vervolgens enkele annotaties aan een klas toevoegen:
@RetentionAnnotation @Deprecated openbare klasse AnnotatedClass {}
Nu kunnen we nadenken AnnotatedClass om te zien hoeveel annotaties worden bewaard:
@Test openbare leegte whenAnnotationRetentionPolicyRuntime_shouldAccess () {AnnotatedClass anAnnotatedClass = nieuwe AnnotatedClass (); Annotatie [] annotaties = anAnnotatedClass.getClass (). GetAnnotations (); assertThat (annotations.length, is (1)); }
De waarde is 1 omdat @RetentionAnnotation heeft een bewaarbeleid van RUNTIME terwijl @Verouderd niet.
4.3. @Geërfd
In sommige situaties hebben we mogelijk een subklasse nodig om de annotaties aan een bovenliggende klasse te binden.
We kunnen de @Geërfd annotatie om onze annotatie te laten voortplanten van een geannoteerde klasse naar zijn subklassen.
Als we solliciteren @Geërfd op onze aangepaste annotatie en pas deze vervolgens toe op BaseClass:
@Inherited @Target (ElementType.TYPE) @Retention (RetentionPolicy.RUNTIME) public @interface InheritedAnnotation {} @InheritedAnnotation public class BaseClass {} public class DerivedClass breidt BaseClass uit {}
Dan, na het uitbreiden van de BaseClass, zouden we dat moeten zien Afgeleide klasse lijkt tijdens runtime dezelfde annotatie te hebben:
@ Test openbare leegte whenAnnotationInherited_thenShouldExist () {DerivedClass afgeleidClass = nieuwe DerivedClass (); InheritedAnnotation annotatie = afgeleidClass.getClass () .getAnnotation (InheritedAnnotation.class); assertThat (annotatie, instanceOf (InheritedAnnotation.class)); }
Zonder de @Geërfd annotatie, zou de bovenstaande test mislukken.
4.4. @Documented
Standaard documenteert Java niet het gebruik van een annotatie in Javadocs.
Maar we kunnen de @Documented annotatie om het standaardgedrag van Java te wijzigen.
Als we een aangepaste annotatie maken die gebruikmaakt van @Documented:
@Documented @Target (ElementType.FIELD) @Retention (RetentionPolicy.RUNTIME) openbaar @interface ExcelCell {int waarde (); }
En pas het toe op het juiste Java-element:
openbare klasse Medewerker {@ExcelCell (0) openbare tekenreeksnaam; }
Dan de Werknemer Javadoc zal het annotatiegebruik onthullen:
4.5. @Repeatable
Soms kan het handig zijn om dezelfde annotatie meer dan eens op een bepaald Java-element te specificeren.
Vóór Java 7 moesten we annotaties groeperen in een enkele containerannotatie:
@Schedules ({@Schedule (time = "15:05"), @Schedule (time = "23:00")}) void scheduleAlarm () {}
Java 7 bracht echter een schonere aanpak. Met de @Repeatable annotatie, we kunnen een annotatie herhaalbaar maken:
@Repeatable (Schedules.class) publiek @interface Schedule {String time () standaard "09:00"; }
Gebruiken @Repeatable, hebben we ook een containerannotatie nodig. In dit geval zullen we opnieuw gebruiken @Schema's:
openbare @interface Schedules {Schedule [] waarde (); }
Dit lijkt natuurlijk veel op wat we hadden vóór Java 7. Maar de waarde is nu dat de wrapper @Schema's wordt niet meer gespecificeerd wanneer we moeten herhalen @Schema:
@Schedule @Schedule (time = "15:05") @Schedule (time = "23:00") void scheduleAlarm () {}
Omdat Java de annotatie van de wrapper vereist, was het voor ons gemakkelijk om te migreren van pre-Java 7 annotatielijsten naar herhaalbare annotaties.
5. Conclusie
In dit artikel hebben we het gehad over ingebouwde annotaties in Java waarmee elke Java-ontwikkelaar vertrouwd zou moeten zijn.
Zoals altijd zijn alle voorbeelden van het artikel te vinden op GitHub.