注解

一、注解常识

1.1 注解是什么?

注解(Annotation。。注意:Annotation本身在JDK中就是一个Interface ),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

简单来说注解其实就是代码中的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相对应的处理。不过呢,假如没有对这些特殊标记做处理,那注解其实没啥用。

1.2 注解的属性

注解只有成员变量,没有方法
注解不是代码本身的一部分,但是 根据Target说明, 某些注解可以在程序运行的时候接受代码的提取

1.3 JDK内置了哪些注解?

  1. Overried
    Overried是告诉编译器要检查该方法是实现父类的方法。

  2. Deprecated用于标记一些过时的代码。
    
  3. SuppressWarnings
    SuppressWarnings用于消除一些警告信息,使用集合的时候,如果没有指定泛型,IDE会提示安全检查的警告。

  4. FunctionalInterface
    FunctionalInterface是JDK8中的注解,用来指定该接口是函数式接口。

  5. SafeVarargs
    SafeVarargs是JDK 7中的注解,主要目的是处理可变长参数中的泛型,此注解告诉编译器:在可变长参数中的泛型是类型安全的。

泛型的类型安全是怎么回事?

1.4 怎么自定义一个注解?

在Java中,类使用class定义,接口使用interface定义,注解和接口的定义差不多,增加了一个@符号,即@interface,代码如下:

public @interface EnableAuth {
}

注解中可以定义元素,用于信息的描述,跟接口中方法的定义类似,代码如下:

public @interface EnableAuth {
    String name();
}

还可以添加默认值:

public @interface EnableAuth {
    String name() default "enable auth ";
}

可见:注解的元素看起来就像接口的方法,不过你可以为注解的元素设定默认值,JDK8以后,接口也可以定义默认方法了。

上面的介绍只是完成了自定义注解的第一步,开发中日常使用注解大部分是用在类上,方法上,字段上,示列代码如下:

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface EnableAuth {

}

  1. Target
    用于指定被修饰的注解修饰哪些程序单元,也就是上面说的类,方法,字段
  2. Retention
    用于指定被修饰的注解被保留多长时间,分别SOURCE(注解仅存在于源码中,在class字节码文件中不包含),CLASS(默认的保留策略,注解会在class字节码文件中存在,但运行时无法获取),RUNTIME(注解会在class字节码文件中存在,在运行时可以通过反射获取到)三种类型,如果想要在程序运行过程中通过反射来获取注解的信息需要将Retention设置为RUNTIME
  3. Documented
    用于指定被修饰的注解类将被javadoc工具提取成文档
  4. Inherited
    用于指定被修饰的注解类将具有继承性

1.5 注解元素的可用类型

注解时的定义的元素类型不是随意选用的,而是限于下面五种:

  • 所有基本类型(即使是包装类,也不可以!!
  • String
  • enum
  • Annotation
  • class

1.6 注解元素的默认值限制

编译器对注解元素的默认值是有严格限制的,要么给出默认值,要么在使用注解时提供元素值,不能存在不确定的值

  • 默认值不能为null,而且在代码中设定的时候也不能为null,因此,注解元素不能直接表示一个元素的存在、缺失,但是可以用 -1 、空串等表示“不存在”

二、注解案例

demo:定义一个注解,可以用来追踪项目中的用例。若一个方法或一组方法已经实现了某实例的需求,则加上该注解。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {

    int id();

    String desc() default "no desc";
}

public class PasswordUtils {

    @UseCase(id = 1,desc = "at least have one numeric")
    public boolean validate(String password) {
        return password.matches("\\w*\\d\\w*");
    }

    @UseCase(id = 2)
    public String encrypt(String password) {
        return new StringBuilder(password).reverse().toString();
    }

}

上面定义了注解,并且在方法上加上了注解,但这其实还没有卵用,因为没有对应的注解处理器来处理:

public class UseCaseTracker {
    public static void trackUseCases(List<Integer> useCaseIds, Class<?> clazz) {
        for (Method e : clazz.getDeclaredMethods()) {
            UseCase useCase = e.getAnnotation(UseCase.class);
            if (useCase != null) {
                System.out.println(" found use case " + useCase.id() + useCase.desc());
                useCaseIds.remove(useCase.id());
            }
        }

        useCaseIds.forEach(e -> System.out.println(" missing " + e));
    }

    public static void main(String[] args) {
        ArrayList<Integer> useCases = Lists.newArrayList(1, 2, 3, 4);
        trackUseCases(useCases, PasswordUtils.class);
        
    }
}

这个Demo里用到了两个比较重要的API:

  1. getAnnotation()
  2. getDeclaredMethods()

三、apt技术

APT技术,从Java6开始到Java7,已经确认过时了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值