java注解

前言

这两天在自己学习着写一个小型的web框架,有点像spring,但是有是轻量级的.里面用到的注解功能.但是对于自定义注解这块又不熟悉,所以专门学习了一波,做点笔记记下来.

概述

注解是自带的.jdk中本身就有很多内置注解,比如override等等.注解的功能其实就是为一些加了注解的类,方法等赋予一些特别的含义.java中有4中元注解
@Target中的参数表示注解应该用在什么地方,参数类型有

  • TYPE 类,接口(包括注解类型)或enum类型
  • FIELD 声明在字段上(包括enum实例)
  • METHOD,声明在方法上
  • PARAMETER,声明参数
  • CONSTRUCTOR,构造器的声明
  • LOCAL_VARIABLE,局部变量声明
  • ANNOTATION_TYPE,注解累心声明
  • PACKAGE,声明在包上

@Rentention注解 表示需要在什么级别保存该注解信息,就是注解的生命周期.参数RetentionPolicy

  • SOURCE 只保留在源文件中,被编译器丢弃
  • CLASS 注解在class文件中可用,但会被VM丢弃
  • RUNTIME 运行时保存,可以通过反射获得信息

@Document 将注解包含在Javadoc中
@Inherited 允许子类继承父类中的注解

举个例子,

1
2
3
4
5
6
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface UseCases{
public String id();
public String description() default "no description";
}

这是个声明在方法级别上的注解,使用了这个注解的方法,可以通过反射来获得注解中的内容.如下

1
2
3
4
5
6
7
8
9
10
11
12
class beanUtil{
//在这里使用了注解
@UseCases(id = "123",description = "123的description")
public boolean valipassword(String password){
return (password.matches("\\w*\\d\\w*"));
}

@UseCases(id ="48")
public String encryptPassword(String password) {
return new StringBuilder(password).reverse().toString();
}
}

下面看测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static void main(String[] args) {
List<Integer> useCases = new ArrayList<Integer>();
Collections.addAll(useCases, 47, 48, 49, 50);
trackUseCases(useCases, beanUtil.class);
}
public static void trackUseCases(List<Integer> useCases, Class<?> cl) {
//这里通过反射获取到此对象的所有方法,并且在其中找到所有的使用此注解的方法.
for (Method m : cl.getDeclaredMethods()) {
//获得注解的对象
UseCases uc = m.getAnnotation(UseCases.class);
if (uc != null) {
System.out.println("Found Use Case:" + uc.id() + " "
+ uc.description());
useCases.remove(new Integer(uc.id()));
}
}
}

输出
Found Use Case:123 123的description
Found Use Case:48 no description

这里就完成了一个自定义注解的实现了.
在这里主要用到的就是两个 一个是@Target注解,里面指明了此注解要修饰的内容,例如构造器,方法,类等.还有一个是Retention注解,表明了此注解保存在哪里,有只在源码中存在,在class文件中存在,在运行时可以出现.如果要使用反射需要使用RUNTIME类型,在运行中通过反射来获得注解.
注意:注解定义上的内容值允许有String ,基本类型,枚举类型,Annotation类型和Class类型