Tinjauan Anotasi Built-In Java

1. Gambaran keseluruhan

Dalam artikel ini, kita akan membincangkan ciri utama bahasa Java - anotasi lalai yang terdapat di JDK.

2. Apa itu Anotasi

Secara sederhana, anotasi adalah jenis Java yang didahului oleh simbol "@" .

Java mempunyai anotasi sejak rilis 1.5. Sejak itu, mereka telah membentuk cara kami merancang aplikasi kami.

Spring dan Hibernate adalah contoh kerangka kerja yang sangat bergantung pada anotasi untuk membolehkan pelbagai teknik reka bentuk.

Pada dasarnya, anotasi memberikan metadata tambahan kepada kod sumber yang diikatnya . Dengan menambahkan anotasi pada kaedah, antara muka, kelas, atau bidang, kita dapat:

  1. Maklumkan kepada penyusun mengenai amaran dan kesilapan
  2. Manipulasi kod sumber pada masa penyusunan
  3. Ubah suai atau periksa tingkah laku semasa waktu berjalan

3. Anotasi Built-In Java

Setelah kita mengkaji asas-asasnya, mari kita lihat beberapa anotasi yang dihantar dengan inti Java. Pertama, terdapat beberapa maklumat yang menyusun:

  1. @Selamat
  2. @SuppressWarnings
  3. @Diadakan
  4. @SafeVarargs
  5. @Fungsi Fungsi
  6. @ Asli

Anotasi ini menghasilkan atau menyekat amaran dan kesalahan penyusun. Menggunakannya secara konsisten selalunya merupakan amalan yang baik kerana menambahkannya dapat mengelakkan kesalahan pengaturcara di masa hadapan.

The @Override anotasi digunakan untuk menunjukkan bahawa kaedah mengatasi atau Menggantikan kelakuan kaedah yang diwarisi.

@SuppressWarnings menunjukkan bahawa kami ingin mengabaikan amaran tertentu dari bahagian kod. The @SafeVarargs anotasi juga bertindak pada jenis amaran yang berkaitan dengan menggunakan varargs.

The @Deprecated anotasi boleh digunakan untuk menandakan API tidak bertujuan untuk digunakan lagi. Selain itu, anotasi ini telah dipasang di Java 9 untuk mewakili lebih banyak maklumat mengenai penghentian tersebut.

Untuk semua ini, anda boleh mendapatkan maklumat yang lebih terperinci dalam artikel yang dipautkan.

3.1. @Fungsi Fungsi

Java 8 membolehkan kita menulis kod dengan cara yang lebih berfungsi.

Antaramuka Kaedah Abstrak Tunggal adalah sebahagian besar dari ini. Sekiranya kita bermaksud antara muka SAM untuk digunakan oleh lambdas, kita boleh menandakannya sebagai pilihan dengan @FunctionalInterface :

@FunctionalInterface public interface Adder { int add(int a, int b); }

Seperti @Override dengan kaedah, @FunctionalInterface menyatakan niat kami dengan Adder .

Sekarang, sama ada kita menggunakan @FunctionalInterface atau tidak, kita masih boleh menggunakan Adder dengan cara yang sama:

Adder adder = (a,b) -> a + b; int result = adder.add(4,5);

Tetapi, jika kita menambahkan kaedah kedua ke Adder, maka penyusun akan mengeluh:

@FunctionalInterface public interface Adder { // compiler complains that the interface is not a SAM int add(int a, int b); int div(int a, int b); }

Sekarang, ini akan disusun tanpa penjelasan @FunctionalInterface . Jadi, apa yang diberikannya kepada kita?

Seperti @Override , anotasi ini melindungi kita daripada kesilapan pengaturcara masa depan. Walaupun mempunyai lebih daripada satu kaedah di antara muka adalah sah, bukan ketika antarmuka itu digunakan sebagai sasaran lambda. Tanpa penjelasan ini, penyusun akan pecah di puluhan tempat di mana Adder digunakan sebagai lambda. Sekarang, ia hanya berlaku di Adder .

3.2. @ Asli

Pada Java 8, terdapat anotasi baru dalam pakej jot.lang.annotation yang disebut Native. The @Native anotasi hanya terpakai kepada bidang. Ini menunjukkan bahawa medan beranotasi adalah pemalar yang mungkin dirujuk dari kod asli . Contohnya, inilah cara penggunaannya di kelas Integer :

public final class Integer { @Native public static final int MIN_VALUE = 0x80000000; // omitted }

Anotasi ini juga dapat berfungsi sebagai petunjuk bagi alat untuk menghasilkan beberapa fail tajuk tambahan.

4. Meta-Anotasi

Seterusnya, meta-anotasi adalah anotasi yang boleh digunakan untuk anotasi lain.

Sebagai contoh, meta-anotasi ini digunakan untuk konfigurasi anotasi:

  1. @Target
  2. @Retention
  3. @ Diwarisi
  4. @Dokumen
  5. @ Boleh diulang

4.1. @Target

Skop anotasi boleh berbeza-beza berdasarkan keperluan. Walaupun satu anotasi hanya digunakan dengan kaedah, anotasi lain dapat digunakan dengan deklarasi konstruktor dan lapangan.

Untuk menentukan elemen sasaran anotasi tersuai, kita perlu melabelnya dengan anotasi @Target .

@Target boleh berfungsi dengan lapan jenis elemen yang berbeza. Sekiranya kita melihat kod sumber @ SafeVarargs , maka kita dapat melihat bahawa ia mesti dilampirkan hanya pada konstruktor atau kaedah:

@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.CONSTRUCTOR, ElementType.METHOD}) public @interface SafeVarargs { }

4.2. @Retention

Beberapa anotasi dimaksudkan untuk digunakan petunjuk untuk penyusun, sementara yang lain digunakan pada waktu proses.

Kami menggunakan anotasi @Retention untuk menyatakan di mana dalam kitaran hidup program kami anotasi kami berlaku .

To do this, we need to configure @Retention with one of three retention policies:

  1. RetentionPolicy.SOURCE – visible by neither the compiler nor the runtime
  2. RetentionPolicy.CLASS – visible by the compiler
  3. RetentionPolicy.RUNTIME – visible by the compiler and the runtime

@Retention defaults to RetentionPolicy.SOURCE.

If we have an annotation that should be accessible at runtime:

@Retention(RetentionPolicy.RUNTIME) @Target(TYPE) public @interface RetentionAnnotation { }

Then, if we add some annotations to a class:

@RetentionAnnotation @Deprecated public class AnnotatedClass { }

Now we can reflect on AnnotatedClass to see how many annotations are retained:

@Test public void whenAnnotationRetentionPolicyRuntime_shouldAccess() { AnnotatedClass anAnnotatedClass = new AnnotatedClass(); Annotation[] annotations = anAnnotatedClass.getClass().getAnnotations(); assertThat(annotations.length, is(1)); }

The value is 1 because @RetentionAnnotation has a retention policy of RUNTIME while @Deprecated doesn't.

4.3. @Inherited

In some situations, we may need a subclass to have the annotations bound to a parent class.

We can use the @Inherited annotation to make our annotation propagate from an annotated class to its subclasses.

If we apply @Inherited to our custom annotation and then apply it to BaseClass:

@Inherited @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface InheritedAnnotation { } @InheritedAnnotation public class BaseClass { } public class DerivedClass extends BaseClass { }

Then, after extending the BaseClass, we should see that DerivedClass appears to have the same annotation at runtime:

@Test public void whenAnnotationInherited_thenShouldExist() { DerivedClass derivedClass = new DerivedClass(); InheritedAnnotation annotation = derivedClass.getClass() .getAnnotation(InheritedAnnotation.class); assertThat(annotation, instanceOf(InheritedAnnotation.class)); }

Without the @Inherited annotation, the above test would fail.

4.4. @Documented

By default, Java doesn't document the usage of an annotation in Javadocs.

But, we can use the @Documented annotation to change Java's default behavior.

If we create a custom annotation that uses @Documented:

@Documented @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ExcelCell { int value(); }

And, apply it to the appropriate Java element:

public class Employee { @ExcelCell(0) public String name; }

Then, the Employee Javadoc will reveal the annotation usage:

4.5. @Repeatable

Sometimes it can be useful to specify the same annotation more than once on a given Java element.

Before Java 7, we had to group annotations together into a single container annotation:

@Schedules({ @Schedule(time = "15:05"), @Schedule(time = "23:00") }) void scheduledAlarm() { }

However, Java 7 brought a cleaner approach. With the @Repeatable annotation, we can make an annotation repeatable:

@Repeatable(Schedules.class) public @interface Schedule { String time() default "09:00"; }

To use @Repeatable, we need to have a container annotation, too. In this case, we'll reuse @Schedules:

public @interface Schedules { Schedule[] value(); }

Of course, this looks a lot like what we had before Java 7. But, the value now is that the wrapper @Schedules isn't specified anymore when we need to repeat @Schedule:

@Schedule @Schedule(time = "15:05") @Schedule(time = "23:00") void scheduledAlarm() { }

Because Java requires the wrapper annotation, it was easy for us to migrate from pre-Java 7 annotation lists to repeatable annotations.

5. Conclusion

Dalam artikel ini, kita telah membincangkan anotasi bawaan Java yang semestinya biasa bagi setiap pembangun Java.

Seperti biasa, semua contoh artikel boleh didapati di GitHub.