72

Java 注解用注解标记@Target以声明可以由该注解修饰的可能连接点。枚举的值TYPE, FIELD,METHODElementType清晰易懂。

问题

为什么@Target(ANNOTATION_TYPE)使用价值?带注释的注释有什么用?他们的贡献是什么?解释一下它是如何工作的以及我为什么要使用它。一些已经存在且众所周知的使用示例也会很棒。

4

5 回答 5

43

您可以使用带注释的注释来创建元注释,例如考虑@TransactionalSpring 中的这种用法:

/**
 * Shortcut and more descriptive "alias" for {@code @Transactional(propagation = Propagation.MANDATORY)}.
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(propagation = Propagation.MANDATORY)
public @interface RequiresExistingTransaction {
}

当您启用 Spring 来处理@Transactional注解时,它将查找带有它的类和方法@Transactional 或其任何元注解(带有注解的注解@Transactional)。

无论如何,这只是一个如何使用带注释的注释的具体示例。我想这主要是像 Spring 这样的框架,使用它们是有意义的。

于 2013-02-26T23:03:09.727 回答
7

由 注释的每个注释@Target(ElementType.ANNOTATION_TYPE)都称为Meta-annotation。这意味着,您可以定义自己的自定义注释,将许多注释合并为一个注释以创建composed annotations.

Android世界的一个很好的例子是StringDef

表示带注释的 String 元素表示一种逻辑类型,并且它的值应该是显式命名的常量之一。

@Retention(SOURCE)
@StringDef({POWER_SERVICE, WINDOW_SERVICE, LAYOUT_INFLATER_SERVICE}) 
public @interface ServicesName {}

public static final String POWER_SERVICE = "power";
public static final String WINDOW_SERVICE = "window";
public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";

代码检查员将@ServicesName@WeekDays以相同的方式处理@StringDef。因此,我们可以根据需要创建尽可能多的named StringDef并覆盖一组常量。@Target(ElementType.ANNOTATION_TYPE)它是一个允许扩展注释使用的工具。

于 2018-03-04T19:26:07.850 回答
3

例如,如果注释看起来像

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeAnnotation {

    String description() default "This is example for class annotation";
}

在这种情况下编译器会抱怨

@SomeAnnotation
public class SomeClass {

    @SomeAnnotation    // here it's complaning
    public void someMethod(){}
}

如果你改变

@Target(ElementType.TYPE) 

@Target({ElementType.METHOD, ElementType.TYPE}) 

它不会再抱怨了。

于 2014-07-18T12:30:40.797 回答
1
  1. 为什么要使用@Target(ANNOTATION_TYPE) 值?

简单地说:当需要将注解应用于另一个注解时。如果您查看常见 Java 注释的源代码,您会经常看到以下代码模式:

@Target(ANNOTATION_TYPE)
public @interface TheAnnotation
{
  ...
}

例如,

@Documented 
@Target({ ANNOTATION_TYPE }) 
@Retention(RUNTIME) 
public @interface Constraint { 
public Class<? extends ConstraintValidator<?, ?>>[] validatedBy(); 
}
  1. 带注释的注释有什么用?

如果在另一个注释(定义)类中使用该注释,它们是好的或更确切地说是必要的。

  1. 他们的贡献是什么?

它们可以将注释直接应用于另一个注释,这与将注释应用于标准 Java 类或类方法等不同。

  1. 解释一下它是如何工作的以及我为什么要使用它。

例如,如果您创建一个数据模型类并希望它检查数据的有效性,则可能需要在某些注解定义类中的@Target 注解中具有这样的值。通过向类添加注释很容易包括这些数据有效性检查:某些值不为空(@notNull),电子邮件有效(@ValidEmail),字段长度超过 x 个字符(@Size)等。有有许多现成的注释可以进行数据有效性检查,但不一定适用于所有目的,例如,如果您想通过添加注释 @PasswordMatches 来检查密码及其匹配密码是否相同。这可以通过创建注释类 PasswordMatches 来实现:

@Target({TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = PasswordMatchesValidator.class)
@Documented
public @interface PasswordMatches {

    String message() default "Passwords don't match";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

 }

注意有线

@Constraint(validatedBy = PasswordMatchesValidator.class)

即注释包含在这个注释定义类中。

PasswordMatchesValidator 类可能如下所示:

public class PasswordMatchesValidator implements ConstraintValidator<PasswordMatches, Object> {

@Override
public void initialize(final PasswordMatches constraintAnnotation) {}

@Override
public boolean isValid(final Object obj, final ConstraintValidatorContext context) {
    final UserDto user = (UserDto) obj;
    return user.getPassword().equals(user.getMatchingPassword());
    }
}

现在密码相等检查很容易通过添加注释@PasswordMatches 包含到数据模型类中:

@PasswordMatches 
public class UserDto {
... 
}

请注意,仅通过将注释@PasswordMatches 添加到类中才能进行密码检查,并且PasswordMatches 注释类需要具有@Constraint(validatedBy = PasswordMatchesValidator.class) 行。换句话说,一个注解用于注解另一个注解。这是可能的,因为@Constraint 注释(定义)类具有@Target({ ANNOTATION_TYPE }) 行。

注释注释的主要原因是使在注释(定义)类中使用注释成为可能。特别是,如果您想使用注释自定义注释,则需要将 ANNOTATION_TYPE 包含到 @Target 注释值数组到自定义注释类中。

  1. 一些已经存在且众所周知的使用示例也会很棒。

在第 4 项中有一个非常著名的示例,但另一个用于注释的已知注释(并且其实现必须具有 @Target(ANNOTATION_TYPE) 行)是 @Retention、@Documented 和 @Target 本身。

于 2020-02-14T23:25:02.237 回答
-4

注释基本上是与您的代码一起使用的附加元数据(信息)。它可以与侧面类型(类、接口)、方法和参数一起放置。

它在编译时和运行时通常很有用。许多流行的 API(例如 Java EE 5+、Spring、AspectJ)利用注释来提高代码的清晰度和一致性。

使用注解通常可以让代码更易读、更容易理解。

我建议您通读 Java 教程的注释章节

过去,元数据通常以 xml 文件的形式提供,如果必须查找不同的 xml 配置文件,则很难理解代码。最新的Java servlet API 允许简单地通过使用注解来映射 servlet——而不是 web.xml 映射

@WebServlet("/response")
public class ResponseServlet extends HttpServlet {
  // servlet code here...
}
于 2013-02-26T23:13:03.010 回答