Введение в аннотации
J2SE содержит множество нововведений в самом языке Java, в том числе поддержка параметризуемых классов (generics) и улучшенного цикла for (enhanced for loop). В предыдущих статьях мы подробно рассказывали о параметризуемых классах и об улученном цикле for, а в этой статье мы рассмотрим аннотации, встроенные в J2SE 5.0.
В этой статье:
Что же такое аннотации? Аннотации - они же JSR-175 (Meta-data) - позволяют связывать метаданные с программными элементами (такими как классы, интерфейсы и методы). Они могут служить дополнительными модификаторами без изменения основного кода для своих элементов.
Само введение метаданных в исходный код не является новым для J2SE 5.0. Вы можете добавить тег @deprecated в комментариях к методу в javadoc, и компилятор будет обрабатывать его как метаданные метода. Такая возможность появилась с выходом версии J2SE 1.0. Уже начальный релиз платформы был ориентирован на сокращение использования метода getenv() (хотя это было реализовано только в версии 1.1). Суть осталась той же, за исключением символа @ в синтаксисе. Изменилось только место -- тег аннотации перешел в код, а не в комментарий. Преимущество в том, что аннотации являются способом поддержки программной модели объявлений.
Итак, первая аннотация, которая идет с J2SE 5.0: @Deprecated. Обратите внимание, что здесь заглавная буква D. @Deprecated функционально работает в коде также как и @deprecated в javadoc, связанный с классом или методом. С помощью флагов и тега @Deprecated вы сообщаете компьютеру предупредить пользователя, что используется тот или иной класс или метод.
Класс Main содержит метод deprecatedMethod(), у которого флагом является аннотация @Deprecated, а комментарием @deprecated:
public class Main {
/**
* @deprecated устарел. Используйте вместо него Use System.foobar().
*/
@Deprecated
public static void deprecatedMethod() {
System.out.println("Don't call me");
}
}Компилируйте класс с аннотацией так же, как без нее:
> javac Main.javaКак и следовало ожидать, получился класс Main.class.
Если вы используете метод deprecated, то получите предупреждение при компиляции - такое же, как при использовании тега @deprecated в javadoc. Пример:
public class User {
public static void main(String args[]) {
Main.deprecatedMethod();
}
}Скомпилируется:
> javac User.javaи вы увидите следующее предупреждение об использовании класса deprecated:
Note: User.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.User.java использует или заменяет deprecated API. Перекомпилируйте с -Xlint:deprecation, чтобы посмотреть детали. Добавление -Xlint в строку компиляции покажет, что именно не так:
> javac -Xlint:deprecation User.java
User.java:3: warning: [deprecation] deprecatedMethod() in
Main has been deprecated
Main.deprecatedMethod();
^
1 warningЗамена комментария @deprecated на аннотацию @Deprecated не принесет ничего существенно нового в систему. Это слега изменяет способ, но делает все то же самое. А вот следующие две аннотации @Override и @SuppressWarnings действительно меняют функциональность платформы.
Аннотация @Override может использоваться вместе с объявлением метода. После того как вы ввели имя, можете добавить аннотацию @Override для установки значение флага функции, чтобы переписать метод суперкласса. Зачем так делать? Чтобы найти ошибку раньше. Сколько раз вы собирались переписать метод, но то в названии метода была ошибка, то определены неправильные аргументы, а то неверный тип возвращаемого значения? Иными словами, сколько раз вам приходилось создавать новый метод вместо того, чтобы переписать уже существующий? Используя @Override, вы найдете ошибку в текущем классе намного раньше:
public class Overrode {
@Override
public int hashcode() {
return 0;
}
@Override
public boolean equals(Object o) {
return true;
}
}Здесь ошибка в том, что название метода должно быть hashCode, а не hashcode. Предполагается, что объявление метода находится где-то в описании класса. Если не использовать первую аннотацию @Override, сколько у вас займет времени, чтобы обнаружить, что ваш метод hashCode (с заглваной буквой) не вызывается, и вы получаете некоторый результат по умолчанию от родительского класса Object. Благодаря аннотации @Override, компиляция класса выдаст ошибку, сообщающую вам о проблеме (метод не переписывается из своего суперкласса):
> javac Overrode.java
Overrode.java:2: method does not override a method from its
superclass
@Override
^
1 errorЧем скорее вы найдете ошибку такого происхождения, время на ее исправление сильно сокращается. Обратите внимание, что метод hashCode никогда не возвращает константу. Более подробное описание использования hashCode и equals() вы найдете в 8 пункте в книге Джошуа Блош "Путеводитель по эффективному программированию на Java".
Последняя из трех новых аннотаций в J2SE 5.0 - @SuppressWarnings - самая интересная. Она сообщает компилятору не предупреждать вас, о чем он обычно предупреждает. Предупреждения относятся к разным категориям, и вы можете сообщить аннотации, какие категории вас интересуют. Компилятор javac определяет семь свойств для вывода предупреждений: все, deprecation, непроверенные, проход при невыполнении условия, неверные пути, последовательные и конечные. (В спецификации языка определены только два из этих типов: deprecation и непроверенные.)
В целях демонстрации, посмотрим на блокировку опции "проход при невыполненных условиях". Начнем со следующего класса. В этом классе пропущено break в каждом случае switch:
public class Fall {
public static void main(String args[]) {
int i = args.length;
switch (i) {
case 0:
System.out.println("0");
case 1:
System.out.println("1");
case 2:
System.out.println("2");
case 3:
System.out.println("3");
default:
System.out.println("Default");
}
}
}Скомпилируйте класс с помощью javac. Вы увидите, что просто создается файл .class без всяких предупреждений:
javac Fall.javaЕсли вы хотите, чтобы компилятор предупреждал вас о невыполнении условий switch (т.е. что пропущено одно или более утверждений break), скомпилируйте с опцией Xlint:fallthrough :
javac -Xlint:fallthrough Fall.javaВы увидите следующие предупреждения:
Fall.java:6: warning: [fallthrough] possible fall-through into case case 1: System.out.println("1"); ^ Fall.java:7: warning: [fallthrough] possible fall-through into case case 2: System.out.println("2"); ^ Fall.java:8: warning: [fallthrough] possible fall-through into case case 3: System.out.println("3"); ^ Fall.java:9: warning: [fallthrough] possible fall-through into case default : System.out.println("Default"); ^ 4 warningsЧто делать, если вы не придаете значения тому, что в каждом случае switch пропускается break? Вот где вам пригодится аннотация @SuppressWarnings. Вставьте эту строчку перед объявлением метода main():
@SuppressWarnings("fallthrough")Скомпилируйте с опцией -Xlint:fallthrough:
javac -Xlint:fallthrough Fall.java и получите файл .class без единого предупреждения.
Аннотация @SuppressWarnings может использоваться для подавления других предупреждений, например, когда вы используете коллекции, не указывая типа данных элементов коллекции. Не стоит использовать аннотацию @SuppressWarnings, чтобы просто избежать предупреждений компилятора. Применяйте это там, где нельзя избежать предупреждений, например, при использовании библиотеки, которая не была создана вместе с параметризуемыми классами (generics).
Это что касается встраиваемых аннотаций. Маленькое дополнение: аннотации (со своими аргументами) обычно определяются отдельной строкой сами по себе.
Определяя свои собственные аннотации, вы можете сделать намного больше, чем просто использовать аннотации, введенные в J2SE 5.0. Здесь вы узнаете, как создавать свои аннотации.
Теги: annotationsjava 5