← Назад к вопросам
Что такое аннотации в Java? Как создать свою аннотацию?
2.0 Middle🔥 171 комментариев
#Docker, Kubernetes и DevOps#JVM и управление памятью
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Аннотации в Java
Аннотации — это форма метаданных, которые предоставляют информацию о коде, но не являются частью самого кода. Они не прямо влияют на выполнение кода, но могут использоваться инструментами, фреймворками и компилятором для обработки информации.
Встроенные аннотации
Java содержит несколько встроенных аннотаций:
@Override // указывает, что метод переопределяет метод из базового класса
@Deprecated // указывает, что код устарел и больше не рекомендуется
@SuppressWarnings // указывает компилятору игнорировать определённые предупреждения
@FunctionalInterface // указывает, что интерфейс функциональный
Примеры использования:
class Animal {
public void makeSound() {
System.out.println("Some sound");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof");
}
@Deprecated
public void oldMethod() {
System.out.println("This is deprecated");
}
}
public class Main {
public static void main(String[] args) {
@SuppressWarnings("unchecked")
List rawList = new ArrayList(); // компилятор не выдаст warning
}
}
Метааннотации
Метааннотации — это аннотации для аннотаций. Они определяют, как работают другие аннотации:
@Retention // указывает, как долго аннотация сохраняется
@Target // указывает, к чему можно применить аннотацию
@Documented // указывает, что аннотация будет включена в Javadoc
@Inherited // указывает, что аннотация наследуется подклассами
Repeatable // указывает, что аннотация может быть применена несколько раз
Значения @Retention:
RetentionPolicy.SOURCE— удаляется после компиляцииRetentionPolicy.CLASS— сохраняется в .class файле, но не доступна в runtimeRetentionPolicy.RUNTIME— доступна во время выполнения (через reflection)
Значения @Target:
ElementType.TYPE— для классов, интерфейсов, enumElementType.FIELD— для полейElementType.METHOD— для методовElementType.PARAMETER— для параметров методовElementType.CONSTRUCTOR— для конструкторовElementType.LOCAL_VARIABLE— для локальных переменных
Создание собственной аннотации
Пример 1: Простая аннотация для валидации
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface NotEmpty {
String message() default "Поле не должно быть пустым";
}
Пример 2: Более сложная аннотация
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
public @interface ApiEndpoint {
String path();
String[] methods() default {"GET"};
String description() default "";
boolean requiresAuth() default true;
}
Использование собственных аннотаций
@ApiEndpoint(
path = "/users",
methods = {"GET", "POST"},
description = "Получение списка пользователей",
requiresAuth = true
)
public class UserController {
@ApiEndpoint(
path = "/users/{id}",
methods = {"GET"},
description = "Получение пользователя по ID"
)
public User getUser(String id) {
return new User(id);
}
}
Обработка аннотаций в runtime
import java.lang.reflect.*;
public class AnnotationProcessor {
public static void processAnnotations(Class<?> clazz) {
// Проверяем аннотации класса
if (clazz.isAnnotationPresent(ApiEndpoint.class)) {
ApiEndpoint endpoint = clazz.getAnnotation(ApiEndpoint.class);
System.out.println("Path: " + endpoint.path());
System.out.println("Methods: " + Arrays.toString(endpoint.methods()));
System.out.println("Description: " + endpoint.description());
}
// Проверяем аннотации методов
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(ApiEndpoint.class)) {
ApiEndpoint endpoint = method.getAnnotation(ApiEndpoint.class);
System.out.println("Method: " + method.getName());
System.out.println("Path: " + endpoint.path());
}
}
// Проверяем аннотации полей
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(NotEmpty.class)) {
NotEmpty notEmpty = field.getAnnotation(NotEmpty.class);
System.out.println("Field: " + field.getName());
System.out.println("Message: " + notEmpty.message());
}
}
}
}
Валидация с собственной аннотацией
public class User {
@NotEmpty(message = "Имя пользователя не может быть пустым")
private String username;
@NotEmpty
private String email;
public User(String username, String email) {
this.username = username;
this.email = email;
}
}
public class Validator {
public static boolean validate(Object obj) {
Class<?> clazz = obj.getClass();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(NotEmpty.class)) {
field.setAccessible(true);
try {
Object value = field.get(obj);
if (value == null || (value instanceof String && ((String) value).isEmpty())) {
NotEmpty annotation = field.getAnnotation(NotEmpty.class);
System.out.println(annotation.message());
return false;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return true;
}
}
Практическое применение
public class Main {
public static void main(String[] args) {
// Валидация
User user1 = new User("", "test@example.com");
System.out.println("User1 valid: " + Validator.validate(user1)); // false
User user2 = new User("john", "john@example.com");
System.out.println("User2 valid: " + Validator.validate(user2)); // true
// Обработка аннотаций
AnnotationProcessor.processAnnotations(UserController.class);
}
}
Где используются аннотации?
- JUnit — @Test, @Before, @After
- Spring — @Autowired, @Service, @Repository, @RequestMapping
- Hibernate — @Entity, @Column, @Id
- JAX-RS — @Path, @GET, @POST
- Project Lombok — @Data, @Getter, @Setter
Примечания
- Аннотации НЕ влияют на выполнение кода напрямую
- Они используются для метапрограммирования и инструментов обработки
- Runtime аннотации требуют обработки через reflection
- При создании аннотаций всегда используй
@Retention(RetentionPolicy.RUNTIME)если нужна обработка в runtime
Аннотации — мощный инструмент для создания фреймворков, библиотек и для делегирования повторяющихся задач инструментам вместо написания кода вручную.