English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
В этом уроке мы будем изучать различные типы Java анализаторов с помощью примеров.
Java анализаторы — это метаданные нашего исходного кода (данные о данных). Java SE предоставляет несколько предопределенных анализаторов. Кроме того, мы можем создавать пользовательские анализаторы по мере необходимости.
Если вы не знаете, что такое анализаторы, пожалуйста, посетитеJava аннотацииУрок.
Эти анализаторы можно классифицировать как:
1. Предопределенные анализаторы
@Deprecated
@Override
@SuppressWarnings
@SafeVarargs
@FunctionalInterface
2. Пользовательские аннотации
3. Мета-аннотации
@Retention
@Documented
@Target
@Inherited
@Repeatable
@Deprecated анализатор — это маркер анализатора, указывающий на элементы (классы, методы, поля и т.д.), которые устарели и были заменены обновленными элементами.
ее грамматика такова:
@Deprecated accessModifier returnType deprecatedMethodName() { ... }
Когда программа использует элементы, объявленные как弃нутые, компилятор генерирует предупреждение.
Мы используем метку @deprecated в Javadoc для записи элементов, которые были弃нуты.
/** * @deprecated * Почему он был弃нут */ @Deprecated accessModifier returnType deprecatedMethodName() { ... }
class Main { /** * @deprecated * Этот метод弃用了, и его заменил newMethod() */ @Deprecated public static void deprecatedMethod() { System.out.println("Deprecated method"); } public static void main(String args[]) { deprecatedMethod(); } }
Результат вывода
Устаревший метод
@Override анализатор определяет метод подкласса, который перекрывает метод родительского класса с тем же именем, типом возвращаемого значения и списком параметров.
@Override не обязательно использовать при переопределении методов. Но если его использовать, то при возникновении ошибок (например, неправильный тип параметра) компилятор выдаст ошибку.
class Animal { // Переопределение метода public void display(){ System.out.println("Я животное"); } } class Dog extends Animal { // Переопределение метода @Override public void display(){ System.out.println("Я собака"); } public void printMessage(){ display(); } } class Main { public static void main(String[] args) { Dog dog1 = new Dog(); dog1.printMessage(); } }
Результат вывода
Я собака
В этом примере, создав объект класса Dog dog1, мы можем вызвать его метод printMessage(), после чего этот метод выполняет оператор display().
Поскольку метод display() определен в обоих классах, метод display() подкласса Dog будет перекрывать метод display() суперкласса Animal. Таким образом, вызывается метод подкласса.
Как следует из названия, @SuppressWarnings аннотация указывает компилятору на禁止 отображения предупреждений, генерируемых при выполнении программы.
Мы можем определить типы предупреждений, которые нужно отменить. Запрещенные предупреждения специфичны для компилятора, но предупреждения делятся на две категории:устаревшее и Не проверено.
Чтобы запретить отображение конкретной категории предупреждений, мы намеренно используем:
@SuppressWarnings("warningCategory")
Например,
@SuppressWarnings("deprecated")
Чтобы запретить отображение множества категорий предупреждений, мы намеренно используем:
@SuppressWarnings({"warningCategory1", "warningCategory2"})
Например,
@SuppressWarnings({"deprecated", "unchecked"})
Когда мы используем не рекомендованные элементы, deprecated категория указывает компилятору на禁止 отображения предупреждений.
Когда мы используем исходные типы, unchecked категория указывает компилятору на禁止 отображения предупреждений.
Итак, неопределенные предупреждения будут игнорироваться. Например,
@SuppressWarnings("someundefinedwarning")
class Main { @Deprecated public static void deprecatedMethod() { System.out.println("Deprecated method"); } @SuppressWarnings("deprecated") public static void main(String args[]) { Main depObj = new Main(); depObj. deprecatedMethod(); } }
Результат вывода
Устаревший метод
В этом примере deprecatedMethod() был помечен как устаревший, и при его использовании будет выдаваться компиляторное предупреждение. Используя аннотацию @SuppressWarnings("deprecated"), мы можем избежать компиляторного предупреждения.
Аннотация @SafeVarargs утверждает, что метод или конструктор с аннотацией не выполняет не безопасные операции с его переменными параметрами (изменяемыми параметрами).
Мы можем использовать эту аннотацию только в методах или конструкторах, которые не могут быть переопределены. Это связано с тем, что переопределение их может привести к выполнению не безопасных операций.
До Java 9 мы могли использовать эту аннотацию только в final или static методах, так как их нельзя переопределить. Теперь мы можем использовать эту аннотацию и в частных методах.
import java.util.*; class Main { private void displayList(List<String>... lists) { for (List<String> list : lists) { System.out.println(list); } } public static void main(String args[]) { Main obj = new Main(); List<String> universityList = Arrays.asList("Tribhuvan University", "Kathmandu University"); obj.displayList(universityList); List<String> programmingLanguages = Arrays.asList("Java", "C"); obj.displayList(universityList, programmingLanguages); } }
Предупреждения
Типовая безопасность: Возможное загрязнение стека через varargs параметрные списки Типовая безопасность: Создается массив generic List<String> для varargs параметр
Результат вывода
Примечание: Main.java использует не проверенные или опасные операции. [Университет Tribhuvan, Университет Kathmandu] [Университет Tribhuvan, Университет Kathmandu] [Java, C]
Здесь List ... list specifies the type of a variable-length parameter of type List. Это означает, что метод displayList() может иметь ноль или несколько параметров.
Программа компилируется без ошибок, но при отсутствии аннотации @SafeVarargs будет выдаваться предупреждение.
При использовании аннотации @SafeVarargs в предыдущем примере
@SafeVarargs private void displayList(List<String>... lists) { ... }
Мы получаем такой же вывод, но без предупреждений. При использовании этой аннотации также удаляются не проверенные предупреждения.
Java 8 впервые ввел эту аннотацию @FunctionalInterface. Эта аннотация указывает, что тип, для которого она используется, является функциональным интерфейсом. Функциональный интерфейс может иметь только один абстрактный метод.
@FunctionalInterface public interface MyFuncInterface{ public void firstMethod(); // это абстрактный метод }
Если мы добавим еще один абстрактный метод, то
@FunctionalInterface public interface MyFuncInterface{ public void firstMethod(); // это абстрактный метод public void secondMethod(); // это вызовет компиляционную ошибку }
Теперь, когда мы запустим программу, мы получим следующее предупреждение:
Неожиданная аннотация @FunctionalInterface @FunctionalInterface ^ интерфейс MyFuncInterface не является функциональным интерфейсом Найдены несколько не перекрывающихся абстрактных методов в интерфейсе MyFuncInterface
Использование аннотации @FunctionalInterface не является обязательным. Компилятор будет рассматривать любое интерфейс, удовлетворяющее определению функционального интерфейса, как функциональный интерфейс.
Цель использования этой аннотации - обеспечить, чтобы функциональный интерфейс имел только один абстрактный метод.
Но у него может быть любое количество методов по умолчанию и статических методов, потому что у них есть реализация.
@FunctionalInterface public interface MyFuncInterface{ public void firstMethod(); // Это абстрактный метод default void secondMethod() { ... } default void thirdMethod() { ... } }
Мы также можем создавать свои собственные пользовательские аннотации.
ее грамматика такова:
[Access Specifier] @interface<AnnotationName> { DataType <MethodName>() [default value]; }
Вот информация о пользовательских аннотациях, которую вам нужно знать:
Аннотации можно создавать, используя @interface после имени аннотации.
Аннотации могут иметь элементы,看起来像方法是,но они не реализованы.
Значение по умолчанию является опциональным. Параметр не может быть пустым значением.
Тип возвращаемого значения может быть примитивным,枚举,строка,имя класса или массив этих типов.
@interface MyCustomAnnotation { String value() default "default value"; } class Main { @MyCustomAnnotation(value = "w3codebox") public void method1() { System.out.println("Тестовый метод 1"); } public static void main(String[] args) throws Exception { Main obj = new Main(); obj.method1(); } }
Результат вывода
Тестовый метод 1
Мета-аннотации - это аннотации, применяемые к другим аннотациям.
Аннотация @Retention определяет наиболее высокий уровень доступности этой аннотации.
ее грамматика такова:
@Retention(RetentionPolicy)
Есть три типа:
RetentionPolicy.SOURCE - Комментарии доступны только на уровне исходного кода и игнорируются компилятором.
RetentionPolicy.CLASS - Аннотация доступна компилятору на этапе компиляции, но Java Virtual Machine (JVM) егоignore.
RetentionPolicy.RUNTIME - Аннотация может быть использована JVM.
Например,
@Retention(RetentionPolicy.RUNTIME) public @interface MyCustomAnnotation{ ... }
По умолчанию, пользовательские аннотации не включены в официальную документацию Java. Чтобы включить аннотацию в документацию Javadoc, используйте аннотацию @Documented.
Например,
@Documented public @interface MyCustomAnnotation{ ... }
Мы можем использовать аннотацию @Target, чтобы ограничить аннотацию применением к определенным целям.
ее грамматика такова:
@Target(ElementType)
ElementType может быть одним из следующих типов:
Тип элемента | Target |
---|---|
ElementType.ANNOTATION_TYPE | Тип аннотации |
ElementType.CONSTRUCTOR | Конструктор |
ElementType.FIELD | Поле |
ElementType.LOCAL_VARIABLE | Локальная переменная |
ElementType.METHOD | Метод |
ElementType.PACKAGE | Пакет |
ElementType.PARAMETER | Параметры |
ElementType.TYPE | Используется для описания класса, интерфейса (включая тип аннотации) или объявления enum. |
Например,
@Target(ElementType.METHOD) public @interface MyCustomAnnotation{ ... }
В этом примере мы ограничили использование этой аннотации методами.
Примечание:Если не определен целевой тип, аннотация может быть применена к любому элементу.
По умолчанию, тип аннотации не может наследоваться от суперкласса. Однако, если необходимо наследовать аннотацию от суперкласса к подклассу, можно использовать аннотацию @Inherited.
ее грамматика такова:
@Inherited
Например,
@Inherited public @interface MyCustomAnnotation { ... } @MyCustomAnnotation public class ParentClass{ ... } public class ChildClass extends ParentClass { ... }
Аннотация с меткой @Repeatable может быть применена несколько раз к одному и тому же заявлению.
@Repeatable(Universities.class) public @interface University { String name(); }
Значение, определенное в аннотации @Repeatable, является контейнерной аннотацией. Контейнерная аннотация имеет переменную значения (value) типа массива с повторяющимися аннотациями, как указано выше. Здесь Universities содержит аннотационные типы.
public @interface Universities { University[] value(); }
Теперь, аннотация @University может использоваться несколько раз в одном объявлении.
@University(name = "TU") @University(name = "KU") private String uniName;
Если нужно извлечь данные аннотации, можно использоватьОтражение.
Чтобы извлечь значение аннотации, мы используем методы getAnnotationsByType() или getAnnotations() из反射ного API.